Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <cstddef>
7 : #include <memory>
8 : #include <string>
9 : #include <unordered_map>
10 : #include <unordered_set>
11 :
12 : #include "Parallel/ParallelComponentHelpers.hpp"
13 : #include "Parallel/ReductionDeclare.hpp"
14 : #include "Parallel/TypeTraits.hpp"
15 : #include "Utilities/Functional.hpp"
16 :
17 : /// \cond
18 : namespace db {
19 : template <typename TagsList>
20 : class DataBox;
21 : } // namespace db
22 : template <size_t MaxSize, class Key, class ValueType, class Hash,
23 : class KeyEqual>
24 : class FixedHashMap;
25 : template <size_t Dim, class ValueType>
26 : class DirectionalIdMap;
27 : template <size_t Dim>
28 : class DirectionalId;
29 : namespace Parallel {
30 : template <typename Metavariables>
31 : class CProxy_GlobalCache;
32 : template <typename Metavariables>
33 : class CProxy_Main;
34 : template <typename Metavariables>
35 : class CkIndex_GlobalCache;
36 : template <typename Metavariables>
37 : class CkIndex_Main;
38 : template <typename Metavariables>
39 : class GlobalCache;
40 : template <typename Metavariables>
41 : class Main;
42 : } // namespace Parallel
43 : /// \endcond
44 :
45 : namespace Parallel {
46 0 : namespace charmxx {
47 : /*!
48 : * \ingroup CharmExtensionsGroup
49 : * \brief Class to mark a constructor as a constructor for the main chare.
50 : *
51 : * The main chare must have a constructor that takes a `const
52 : * Parallel::charmxx::MainChareRegistrationConstructor&` as its only argument.
53 : * This constructor is only used to trigger the `RegisterChare::registrar` code
54 : * needed for automatic registration.
55 : * \see RegisterChare
56 : */
57 1 : struct MainChareRegistrationConstructor {};
58 :
59 : /// \cond
60 : struct RegistrationHelper;
61 : extern std::unique_ptr<RegistrationHelper>* charm_register_list;
62 : extern size_t charm_register_list_capacity;
63 : extern size_t charm_register_list_size;
64 : /// \endcond
65 :
66 0 : std::string get_template_parameters_as_string_impl(
67 : const std::string& function_name);
68 :
69 : /*!
70 : * \ingroup CharmExtensionsGroup
71 : * \brief Returns the template parameter as a `std::string`
72 : *
73 : * Uses the __PRETTY_FUNCTION__ compiler intrinsic to extract the template
74 : * parameter names in the same form that Charm++ uses to register entry methods.
75 : * This is used by the generated Singleton, Array, Group and Nodegroup headers,
76 : * as well as in CharmMain.tpp.
77 : */
78 : template <class... Args>
79 1 : std::string get_template_parameters_as_string() {
80 : std::string function_name(static_cast<char const*>(__PRETTY_FUNCTION__));
81 : return get_template_parameters_as_string_impl(function_name);
82 : }
83 :
84 : /*!
85 : * \ingroup CharmExtensionsGroup
86 : * \brief The base class used for automatic registration of entry methods.
87 : *
88 : * Entry methods are automatically registered by building a list of the entry
89 : * methods that need to be registered in the `charm_register_list`. All entry
90 : * methods in the list are later registered in the
91 : * `register_parallel_components` function, at which point the list is also
92 : * deleted.
93 : *
94 : * The reason for using an abstract base class mechanism is that we need to be
95 : * able to register entry method templates. The derived classes keep track of
96 : * the template parameters and override the `register_with_charm` function.
97 : * The result is that there must be one derived class template for each entry
98 : * method template, but since we only have a few entry method templates this is
99 : * not an issue.
100 : */
101 1 : struct RegistrationHelper {
102 0 : RegistrationHelper() = default;
103 0 : RegistrationHelper(const RegistrationHelper&) = default;
104 0 : RegistrationHelper& operator=(const RegistrationHelper&) = default;
105 0 : RegistrationHelper(RegistrationHelper&&) = default;
106 0 : RegistrationHelper& operator=(RegistrationHelper&&) = default;
107 0 : virtual ~RegistrationHelper() = default;
108 :
109 0 : virtual void register_with_charm() const = 0;
110 0 : virtual std::string name() const = 0;
111 0 : virtual bool is_registering_chare() const { return false; };
112 : };
113 :
114 : /*!
115 : * \ingroup CharmExtensionsGroup
116 : * \brief Class used for automatic registration of Charm++ messages.
117 : *
118 : * Entry methods that use Charm++ messages are responsible for registering those
119 : * messages by calling the static `register_with_charm()` function of this
120 : * struct. Because an entry method can be templated on the message type, we
121 : * don't want to accidentally register the same message-type twice. This struct
122 : * will take care of that, rather than having the logic in the entry method
123 : * registration logic.
124 : */
125 : template <typename MessageType>
126 1 : struct RegisterCharmMessage {
127 0 : static void register_with_charm() {
128 : static bool done_registration = false;
129 : if (done_registration) {
130 : return; // LCOV_EXCL_LINE
131 : }
132 : done_registration = true;
133 :
134 : // NOTE: Assumes custom pack/unpack but default allocate.
135 : static std::string name = MessageType::name();
136 : MessageType::base::__register(
137 : name.c_str(), sizeof(MessageType),
138 : reinterpret_cast<CkPackFnPtr>(MessageType::pack),
139 : reinterpret_cast<CkUnpackFnPtr>(MessageType::unpack));
140 : }
141 : };
142 :
143 : /*!
144 : * \ingroup CharmExtensionsGroup
145 : * \brief Derived class for registering parallel components.
146 : *
147 : * Calls the appropriate Charm++ function to register a parallel component.
148 : */
149 : template <typename ParallelComponent>
150 1 : struct RegisterParallelComponent : RegistrationHelper {
151 0 : using chare_type = typename ParallelComponent::chare_type;
152 0 : using charm_type = charm_types_with_parameters<
153 : ParallelComponent,
154 : typename get_array_index<chare_type>::template f<ParallelComponent>>;
155 0 : using ckindex = typename charm_type::ckindex;
156 0 : using algorithm = typename charm_type::algorithm;
157 :
158 0 : RegisterParallelComponent() = default;
159 0 : RegisterParallelComponent(const RegisterParallelComponent&) = default;
160 0 : RegisterParallelComponent& operator=(const RegisterParallelComponent&) =
161 : default;
162 0 : RegisterParallelComponent(RegisterParallelComponent&&) = default;
163 0 : RegisterParallelComponent& operator=(RegisterParallelComponent&&) = default;
164 0 : ~RegisterParallelComponent() override = default;
165 :
166 0 : void register_with_charm() const override {
167 : static bool done_registration{false};
168 : if (done_registration) {
169 : return; // LCOV_EXCL_LINE
170 : }
171 : done_registration = true;
172 : static const std::string parallel_component_name = name();
173 : ckindex::__register(parallel_component_name.c_str(), sizeof(algorithm));
174 : }
175 :
176 0 : bool is_registering_chare() const override { return true; }
177 :
178 0 : std::string name() const override {
179 : return get_template_parameters_as_string<algorithm>();
180 : }
181 :
182 0 : static bool registrar;
183 : };
184 :
185 : /*!
186 : * \ingroup CharmExtensionsGroup
187 : * \brief Derived class for registering chares.
188 : *
189 : * Calls the appropriate Charm++ function to register a chare
190 : *
191 : * The chare that is being registered must have the following in the destructor:
192 : * \code
193 : * (void)Parallel::charmxx::RegisterChare<ChareName,
194 : * CkIndex_ChareName>::registrar;
195 : * \endcode
196 : *
197 : * The main chare must also have a constructor that takes a `const
198 : * Parallel::charmxx::MainChareRegistrationConstructor&` as its only argument.
199 : * This constructor is only used to trigger the `RegisterChare::registrar` code
200 : * needed for automatic registration. The main chare is set up in
201 : * `Parallel::charmxx::register_main_module<Metavariables>`.
202 : */
203 : template <typename Chare, typename CkIndex>
204 1 : struct RegisterChare : RegistrationHelper {
205 0 : RegisterChare() = default;
206 0 : RegisterChare(const RegisterChare&) = default;
207 0 : RegisterChare& operator=(const RegisterChare&) = default;
208 0 : RegisterChare(RegisterChare&&) = default;
209 0 : RegisterChare& operator=(RegisterChare&&) = default;
210 0 : ~RegisterChare() override = default;
211 :
212 0 : void register_with_charm() const override {
213 : static bool done_registration{false};
214 : if (done_registration) {
215 : return; // LCOV_EXCL_LINE
216 : }
217 : done_registration = true;
218 : static const std::string chare_name = name();
219 : CkIndex::__register(chare_name.c_str(), sizeof(Chare));
220 : }
221 :
222 0 : bool is_registering_chare() const override { return true; }
223 :
224 0 : std::string name() const override {
225 : return get_template_parameters_as_string<Chare>();
226 : }
227 :
228 0 : static bool registrar;
229 : };
230 :
231 : /*!
232 : * \ingroup CharmExtensionsGroup
233 : * \brief Derived class for registering simple actions.
234 : *
235 : * Calls the appropriate Charm++ function to register a simple action.
236 : */
237 : template <typename ParallelComponent, typename Action, typename... Args>
238 1 : struct RegisterSimpleAction : RegistrationHelper {
239 0 : using chare_type = typename ParallelComponent::chare_type;
240 0 : using charm_type = charm_types_with_parameters<
241 : ParallelComponent,
242 : typename get_array_index<chare_type>::template f<ParallelComponent>>;
243 0 : using cproxy = typename charm_type::cproxy;
244 0 : using ckindex = typename charm_type::ckindex;
245 0 : using algorithm = typename charm_type::algorithm;
246 :
247 0 : RegisterSimpleAction() = default;
248 0 : RegisterSimpleAction(const RegisterSimpleAction&) = default;
249 0 : RegisterSimpleAction& operator=(const RegisterSimpleAction&) = default;
250 0 : RegisterSimpleAction(RegisterSimpleAction&&) = default;
251 0 : RegisterSimpleAction& operator=(RegisterSimpleAction&&) = default;
252 0 : ~RegisterSimpleAction() override = default;
253 :
254 0 : void register_with_charm() const override {
255 : static bool done_registration{false};
256 : if (done_registration) {
257 : return; // LCOV_EXCL_LINE
258 : }
259 : done_registration = true;
260 : ckindex::template idx_simple_action<Action>(
261 : static_cast<void (algorithm::*)(const std::tuple<Args...>&)>(nullptr));
262 : }
263 :
264 0 : std::string name() const override {
265 : return get_template_parameters_as_string<RegisterSimpleAction>();
266 : }
267 :
268 0 : static bool registrar;
269 : };
270 :
271 : /// \cond
272 : template <typename ParallelComponent, typename Action>
273 : struct RegisterSimpleAction<ParallelComponent, Action> : RegistrationHelper {
274 : using chare_type = typename ParallelComponent::chare_type;
275 : using charm_type = charm_types_with_parameters<
276 : ParallelComponent,
277 : typename get_array_index<chare_type>::template f<ParallelComponent>>;
278 : using cproxy = typename charm_type::cproxy;
279 : using ckindex = typename charm_type::ckindex;
280 : using algorithm = typename charm_type::algorithm;
281 :
282 : RegisterSimpleAction() = default;
283 : RegisterSimpleAction(const RegisterSimpleAction&) = default;
284 : RegisterSimpleAction& operator=(const RegisterSimpleAction&) = default;
285 : RegisterSimpleAction(RegisterSimpleAction&&) = default;
286 : RegisterSimpleAction& operator=(RegisterSimpleAction&&) = default;
287 : ~RegisterSimpleAction() override = default;
288 :
289 : void register_with_charm() const override {
290 : static bool done_registration{false};
291 : if (done_registration) {
292 : return; // LCOV_EXCL_LINE
293 : }
294 : done_registration = true;
295 : ckindex::template idx_simple_action<Action>(
296 : static_cast<void (algorithm::*)()>(nullptr));
297 : }
298 :
299 : std::string name() const override {
300 : return get_template_parameters_as_string<RegisterSimpleAction>();
301 : }
302 :
303 : static bool registrar;
304 : };
305 : /// \endcond
306 :
307 : /*!
308 : * \ingroup CharmExtensionsGroup
309 : * \brief Derived class for registering threaded actions.
310 : *
311 : * Calls the appropriate Charm++ function to register a threaded action.
312 : */
313 : template <typename ParallelComponent, typename Action, typename... Args>
314 1 : struct RegisterThreadedAction : RegistrationHelper {
315 0 : using chare_type = typename ParallelComponent::chare_type;
316 0 : using charm_type = charm_types_with_parameters<
317 : ParallelComponent,
318 : typename get_array_index<chare_type>::template f<ParallelComponent>>;
319 0 : using cproxy = typename charm_type::cproxy;
320 0 : using ckindex = typename charm_type::ckindex;
321 0 : using algorithm = typename charm_type::algorithm;
322 :
323 0 : RegisterThreadedAction() = default;
324 0 : RegisterThreadedAction(const RegisterThreadedAction&) = default;
325 0 : RegisterThreadedAction& operator=(const RegisterThreadedAction&) = default;
326 0 : RegisterThreadedAction(RegisterThreadedAction&&) = default;
327 0 : RegisterThreadedAction& operator=(RegisterThreadedAction&&) = default;
328 0 : ~RegisterThreadedAction() override = default;
329 :
330 0 : void register_with_charm() const override {
331 : static bool done_registration{false};
332 : if (done_registration) {
333 : return; // LCOV_EXCL_LINE
334 : }
335 : done_registration = true;
336 : ckindex::template idx_threaded_action<Action>(
337 : static_cast<void (algorithm::*)(const std::tuple<Args...>&)>(nullptr));
338 : }
339 :
340 0 : std::string name() const override {
341 : return get_template_parameters_as_string<RegisterThreadedAction>();
342 : }
343 :
344 0 : static bool registrar;
345 : };
346 :
347 : /// \cond
348 : template <typename ParallelComponent, typename Action>
349 : struct RegisterThreadedAction<ParallelComponent, Action> : RegistrationHelper {
350 : using chare_type = typename ParallelComponent::chare_type;
351 : using charm_type = charm_types_with_parameters<
352 : ParallelComponent,
353 : typename get_array_index<chare_type>::template f<ParallelComponent>>;
354 : using cproxy = typename charm_type::cproxy;
355 : using ckindex = typename charm_type::ckindex;
356 : using algorithm = typename charm_type::algorithm;
357 :
358 : RegisterThreadedAction() = default;
359 : RegisterThreadedAction(const RegisterThreadedAction&) = default;
360 : RegisterThreadedAction& operator=(const RegisterThreadedAction&) = default;
361 : RegisterThreadedAction(RegisterThreadedAction&&) = default;
362 : RegisterThreadedAction& operator=(RegisterThreadedAction&&) = default;
363 : ~RegisterThreadedAction() override = default;
364 :
365 : void register_with_charm() const override {
366 : static bool done_registration{false};
367 : if (done_registration) {
368 : return; // LCOV_EXCL_LINE
369 : }
370 : done_registration = true;
371 : ckindex::template idx_threaded_action<Action>(
372 : static_cast<void (algorithm::*)()>(nullptr));
373 : }
374 :
375 : std::string name() const override {
376 : return get_template_parameters_as_string<RegisterThreadedAction>();
377 : }
378 :
379 : static bool registrar;
380 : };
381 : /// \endcond
382 :
383 : namespace detail {
384 : template <class T>
385 : struct get_value_type {
386 : using type = T;
387 : };
388 :
389 : template <class T>
390 : struct get_value_type<std::vector<T>> {
391 : using type = T;
392 : };
393 :
394 : template <class Key, class Mapped, class Hash, class KeyEqual, class Allocator>
395 : struct get_value_type<
396 : std::unordered_map<Key, Mapped, Hash, KeyEqual, Allocator>> {
397 : // When sending data it is typical to use `std::make_pair(a, b)` which results
398 : // in a non-const Key type, which is different from what
399 : // `unordered_map::value_type` is (e.g. `std::pair<const Key, Mapped>`). This
400 : // difference leads to issues with function registration with Charm++ because
401 : // when registering `receive_data` methods we register the `inbox_type`'s
402 : // `value_type` (`std::pair<const Key, Mapped>` in this case), not the type
403 : // passed to `receive_data`.
404 : using type = std::pair<Key, Mapped>;
405 : };
406 :
407 : template <size_t Size, class Key, class Mapped, class Hash, class KeyEqual>
408 : struct get_value_type<FixedHashMap<Size, Key, Mapped, Hash, KeyEqual>> {
409 : // When sending data it is typical to use `std::make_pair(a, b)` which results
410 : // in a non-const Key type, which is different from what
411 : // `FixedHashMap::value_type` is (e.g. `std::pair<const Key, Mapped>`). This
412 : // difference leads to issues with function registration with Charm++ because
413 : // when registering `receive_data` methods we register the `inbox_type`'s
414 : // `value_type` (`std::pair<const Key, Mapped>` in this case), not the type
415 : // passed to `receive_data`.
416 : using type = std::pair<Key, Mapped>;
417 : };
418 :
419 : template <size_t Dim, class Mapped>
420 : struct get_value_type<DirectionalIdMap<Dim, Mapped>> {
421 : // When sending data it is typical to use `std::make_pair(a, b)` which results
422 : // in a non-const Key type, which is different from what
423 : // `FixedHashMap::value_type` is (e.g. `std::pair<const Key, Mapped>`). This
424 : // difference leads to issues with function registration with Charm++ because
425 : // when registering `receive_data` methods we register the `inbox_type`'s
426 : // `value_type` (`std::pair<const Key, Mapped>` in this case), not the type
427 : // passed to `receive_data`.
428 : using type = std::pair<DirectionalId<Dim>, Mapped>;
429 : };
430 :
431 : template <class Key, class Hash, class KeyEqual, class Allocator>
432 : struct get_value_type<std::unordered_multiset<Key, Hash, KeyEqual, Allocator>> {
433 : using type = Key;
434 : };
435 :
436 : template <class T>
437 : using get_value_type_t = typename get_value_type<T>::type;
438 : } // namespace detail
439 :
440 : /*!
441 : * \ingroup CharmExtensionsGroup
442 : * \brief Derived class for registering receive_data functions
443 : *
444 : * Calls the appropriate Charm++ function to register a receive_data function.
445 : * There is a bug in Charm++ that doesn't allow default values for entry method
446 : * arguments for groups and nodegroups, so we have to handle the (node)group
447 : * cases separately from the singleton and array cases.
448 : */
449 : template <typename ParallelComponent, typename ReceiveTag, bool UsingMessages>
450 1 : struct RegisterReceiveData : RegistrationHelper {
451 0 : using chare_type = typename ParallelComponent::chare_type;
452 0 : using charm_type = charm_types_with_parameters<
453 : ParallelComponent,
454 : typename get_array_index<chare_type>::template f<ParallelComponent>>;
455 0 : using cproxy = typename charm_type::cproxy;
456 0 : using ckindex = typename charm_type::ckindex;
457 0 : using algorithm = typename charm_type::algorithm;
458 :
459 0 : RegisterReceiveData() = default;
460 0 : RegisterReceiveData(const RegisterReceiveData&) = default;
461 0 : RegisterReceiveData& operator=(const RegisterReceiveData&) = default;
462 0 : RegisterReceiveData(RegisterReceiveData&&) = default;
463 0 : RegisterReceiveData& operator=(RegisterReceiveData&&) = default;
464 0 : ~RegisterReceiveData() override = default;
465 :
466 0 : void register_with_charm() const override {
467 : static bool done_registration{false};
468 : if (done_registration) {
469 : return; // LCOV_EXCL_LINE
470 : }
471 : done_registration = true;
472 : if constexpr (UsingMessages) {
473 : using message_type = typename ReceiveTag::message_type;
474 : ckindex::template idx_receive_data<ReceiveTag>(
475 : static_cast<void (algorithm::*)(message_type*)>(nullptr));
476 : RegisterCharmMessage<message_type>::register_with_charm();
477 : } else {
478 : ckindex::template idx_receive_data<ReceiveTag>(
479 : static_cast<void (algorithm::*)(
480 : const typename ReceiveTag::temporal_id&,
481 : const detail::get_value_type_t<
482 : typename ReceiveTag::type::mapped_type>&,
483 : bool)>(nullptr));
484 : }
485 : }
486 :
487 0 : std::string name() const override {
488 : return get_template_parameters_as_string<RegisterReceiveData>();
489 : }
490 :
491 0 : static bool registrar;
492 : };
493 :
494 : /*!
495 : * \ingroup CharmExtensionsGroup
496 : * \brief Derived class for registering reduction actions
497 : *
498 : * Calls the appropriate Charm++ functions to register a reduction action.
499 : */
500 : template <typename ParallelComponent, typename Action, typename ReductionType>
501 1 : struct RegisterReductionAction : RegistrationHelper {
502 0 : using chare_type = typename ParallelComponent::chare_type;
503 0 : using charm_type = charm_types_with_parameters<
504 : ParallelComponent,
505 : typename get_array_index<chare_type>::template f<ParallelComponent>>;
506 0 : using cproxy = typename charm_type::cproxy;
507 0 : using ckindex = typename charm_type::ckindex;
508 0 : using algorithm = typename charm_type::algorithm;
509 :
510 0 : RegisterReductionAction() = default;
511 0 : RegisterReductionAction(const RegisterReductionAction&) = default;
512 0 : RegisterReductionAction& operator=(const RegisterReductionAction&) = default;
513 0 : RegisterReductionAction(RegisterReductionAction&&) = default;
514 0 : RegisterReductionAction& operator=(RegisterReductionAction&&) = default;
515 0 : ~RegisterReductionAction() override = default;
516 :
517 0 : void register_with_charm() const override {
518 : static bool done_registration{false};
519 : if (done_registration) {
520 : return; // LCOV_EXCL_LINE
521 : }
522 : done_registration = true;
523 : ckindex::template idx_reduction_action<Action, ReductionType>(
524 : static_cast<void (algorithm::*)(const ReductionType&)>(nullptr));
525 : ckindex::template redn_wrapper_reduction_action<Action, ReductionType>(
526 : nullptr);
527 : }
528 :
529 0 : std::string name() const override {
530 : return get_template_parameters_as_string<RegisterReductionAction>();
531 : }
532 :
533 0 : static bool registrar;
534 : };
535 :
536 : template <typename Metavariables, typename InvokeCombine, typename... Tags>
537 0 : struct RegisterPhaseChangeReduction : RegistrationHelper {
538 0 : using cproxy = CProxy_Main<Metavariables>;
539 0 : using ckindex = CkIndex_Main<Metavariables>;
540 0 : using algorithm = Main<Metavariables>;
541 :
542 0 : RegisterPhaseChangeReduction() = default;
543 0 : RegisterPhaseChangeReduction(const RegisterPhaseChangeReduction&) = default;
544 0 : RegisterPhaseChangeReduction& operator=(const RegisterPhaseChangeReduction&) =
545 : default;
546 0 : RegisterPhaseChangeReduction(RegisterPhaseChangeReduction&&) = default;
547 0 : RegisterPhaseChangeReduction& operator=(RegisterPhaseChangeReduction&&) =
548 : default;
549 0 : ~RegisterPhaseChangeReduction() override = default;
550 :
551 0 : void register_with_charm() const override {
552 : static bool done_registration{false};
553 : if (done_registration) {
554 : return; // LCOV_EXCL_LINE
555 : }
556 : done_registration = true;
557 : ckindex::template idx_phase_change_reduction<InvokeCombine, Tags...>(
558 : static_cast<void (algorithm::*)(
559 : const ReductionData<
560 : ReductionDatum<tuples::TaggedTuple<Tags...>, InvokeCombine,
561 : funcl::Identity, std::index_sequence<>>>&)>(
562 : nullptr));
563 : ckindex::template redn_wrapper_phase_change_reduction<InvokeCombine,
564 : Tags...>(nullptr);
565 : }
566 :
567 0 : std::string name() const override {
568 : return get_template_parameters_as_string<RegisterPhaseChangeReduction>();
569 : }
570 :
571 0 : static bool registrar;
572 : };
573 :
574 : /*!
575 : * \ingroup CharmExtensionsGroup
576 : * \brief Derived class for registering GlobalCache::mutate
577 : *
578 : * Calls the appropriate Charm++ function to register the mutate function.
579 : */
580 : template <typename Metavariables, typename GlobalCacheTag, typename Function,
581 : typename... Args>
582 1 : struct RegisterGlobalCacheMutate : RegistrationHelper {
583 0 : using cproxy = CProxy_GlobalCache<Metavariables>;
584 0 : using ckindex = CkIndex_GlobalCache<Metavariables>;
585 0 : using algorithm = GlobalCache<Metavariables>;
586 :
587 0 : RegisterGlobalCacheMutate() = default;
588 0 : RegisterGlobalCacheMutate(const RegisterGlobalCacheMutate&) = default;
589 0 : RegisterGlobalCacheMutate& operator=(const RegisterGlobalCacheMutate&) =
590 : default;
591 0 : RegisterGlobalCacheMutate(RegisterGlobalCacheMutate&&) = default;
592 0 : RegisterGlobalCacheMutate& operator=(RegisterGlobalCacheMutate&&) = default;
593 0 : ~RegisterGlobalCacheMutate() override = default;
594 :
595 0 : void register_with_charm() const override {
596 : static bool done_registration{false};
597 : if (done_registration) {
598 : return; // LCOV_EXCL_LINE
599 : }
600 : done_registration = true;
601 : ckindex::template idx_mutate<GlobalCacheTag, Function>(
602 : static_cast<void (algorithm::*)(const std::tuple<Args...>&)>(nullptr));
603 : }
604 :
605 0 : std::string name() const override {
606 : return get_template_parameters_as_string<RegisterGlobalCacheMutate>();
607 : }
608 :
609 0 : static bool registrar;
610 : };
611 :
612 : /*!
613 : * \ingroup CharmExtensionsGroup
614 : * \brief Derived class for registering the invoke_iterable_action entry method.
615 : * This is a `local` entry method that is only used for tracing the code with
616 : * Charm++'s Projections.
617 : *
618 : * Calls the appropriate Charm++ function to register the invoke_iterable_action
619 : * function.
620 : */
621 : template <typename ParallelComponent, typename Action, typename PhaseIndex,
622 : typename DataBoxIndex>
623 1 : struct RegisterInvokeIterableAction : RegistrationHelper {
624 0 : using chare_type = typename ParallelComponent::chare_type;
625 0 : using charm_type = charm_types_with_parameters<
626 : ParallelComponent,
627 : typename get_array_index<chare_type>::template f<ParallelComponent>>;
628 0 : using cproxy = typename charm_type::cproxy;
629 0 : using ckindex = typename charm_type::ckindex;
630 0 : using algorithm = typename charm_type::algorithm;
631 :
632 0 : RegisterInvokeIterableAction() = default;
633 0 : RegisterInvokeIterableAction(const RegisterInvokeIterableAction&) = default;
634 0 : RegisterInvokeIterableAction& operator=(const RegisterInvokeIterableAction&) =
635 : default;
636 0 : RegisterInvokeIterableAction(RegisterInvokeIterableAction&&) = default;
637 0 : RegisterInvokeIterableAction& operator=(RegisterInvokeIterableAction&&) =
638 : default;
639 0 : ~RegisterInvokeIterableAction() override = default;
640 :
641 0 : void register_with_charm() const override {
642 : static bool done_registration{false};
643 : if (done_registration) {
644 : return; // LCOV_EXCL_LINE
645 : }
646 : done_registration = true;
647 : ckindex::template idx_invoke_iterable_action<Action, PhaseIndex,
648 : DataBoxIndex>(
649 : static_cast<bool (algorithm::*)()>(nullptr));
650 : }
651 :
652 0 : std::string name() const override {
653 : return get_template_parameters_as_string<RegisterInvokeIterableAction>();
654 : }
655 :
656 0 : static bool registrar;
657 : };
658 :
659 : /*!
660 : * \ingroup CharmExtensionsGroup
661 : * \brief Function that adds a pointer to a specific derived class to the
662 : * `charm_register_list`
663 : *
664 : * Used to initialize the `registrar` bool of derived classes of
665 : * `RegistrationHelper`. When the function is invoked it appends the derived
666 : * class to the `charm_register_list`.
667 : *
668 : * \note The reason for not using a `std::vector` is that this did not behave
669 : * correctly when calling `push_back`. Specifically, the final vector was always
670 : * size 1, even though multiple elements were pushed back. The reason for that
671 : * behavior was never tracked down and so in the future it could be possible to
672 : * use a `std::vector`.
673 : */
674 : template <typename Derived>
675 1 : bool register_func_with_charm() {
676 : #ifdef SPECTRE_CHARM_HAS_MAIN
677 : if (charm_register_list_size >= charm_register_list_capacity) {
678 : // clang-tidy: use gsl::owner (we don't use raw owning pointers unless
679 : // necessary)
680 : auto* const t = // NOLINT
681 : new std::unique_ptr<RegistrationHelper>[charm_register_list_capacity +
682 : 10];
683 : for (size_t i = 0; i < charm_register_list_capacity; ++i) {
684 : // clang-tidy: do not use pointer arithmetic
685 : t[i] = std::move(charm_register_list[i]); // NOLINT
686 : }
687 : // clang-tidy: use gsl::owner (we don't use raw owning pointers unless
688 : // necessary)
689 : delete[] charm_register_list; // NOLINT
690 : charm_register_list = t;
691 : charm_register_list_capacity += 10;
692 : }
693 : charm_register_list_size++;
694 : // clang-tidy: do not use pointer arithmetic
695 : charm_register_list[charm_register_list_size - 1] = // NOLINT
696 : std::make_unique<Derived>();
697 : #endif // SPECTRE_CHARM_HAS_MAIN
698 : return true;
699 : }
700 : } // namespace charmxx
701 : } // namespace Parallel
702 :
703 : // clang-tidy: redundant declaration
704 : template <typename ParallelComponent>
705 : bool Parallel::charmxx::RegisterParallelComponent<
706 : ParallelComponent>::registrar = // NOLINT
707 : Parallel::charmxx::register_func_with_charm<
708 : RegisterParallelComponent<ParallelComponent>>();
709 :
710 : // clang-tidy: redundant declaration
711 : template <typename Chare, typename CkIndex>
712 : bool Parallel::charmxx::RegisterChare<Chare, CkIndex>::registrar = // NOLINT
713 : Parallel::charmxx::register_func_with_charm<
714 : RegisterChare<Chare, CkIndex>>();
715 :
716 : // clang-tidy: redundant declaration
717 : template <typename ParallelComponent, typename Action, typename... Args>
718 : bool Parallel::charmxx::RegisterSimpleAction<ParallelComponent, Action,
719 : Args...>::registrar = // NOLINT
720 : Parallel::charmxx::register_func_with_charm<
721 : RegisterSimpleAction<ParallelComponent, Action, Args...>>();
722 :
723 : // clang-tidy: redundant declaration
724 : template <typename ParallelComponent, typename Action>
725 : bool Parallel::charmxx::RegisterSimpleAction<ParallelComponent,
726 : Action>::registrar = // NOLINT
727 : Parallel::charmxx::register_func_with_charm<
728 : RegisterSimpleAction<ParallelComponent, Action>>();
729 :
730 : // clang-tidy: redundant declaration
731 : template <typename ParallelComponent, typename Action, typename... Args>
732 : bool Parallel::charmxx::RegisterThreadedAction<ParallelComponent, Action,
733 : Args...>::registrar = // NOLINT
734 : Parallel::charmxx::register_func_with_charm<
735 : RegisterThreadedAction<ParallelComponent, Action, Args...>>();
736 :
737 : // clang-tidy: redundant declaration
738 : template <typename ParallelComponent, typename Action>
739 : bool Parallel::charmxx::RegisterThreadedAction<ParallelComponent,
740 : Action>::registrar = // NOLINT
741 : Parallel::charmxx::register_func_with_charm<
742 : RegisterThreadedAction<ParallelComponent, Action>>();
743 :
744 : // clang-tidy: redundant declaration
745 : template <typename ParallelComponent, typename ReceiveTag, bool UsingMessages>
746 : bool Parallel::charmxx::RegisterReceiveData<
747 : ParallelComponent, ReceiveTag, UsingMessages>::registrar = // NOLINT
748 : Parallel::charmxx::register_func_with_charm<
749 : RegisterReceiveData<ParallelComponent, ReceiveTag, UsingMessages>>();
750 :
751 : // clang-tidy: redundant declaration
752 : template <typename ParallelComponent, typename Action, typename ReductionType>
753 : bool Parallel::charmxx::RegisterReductionAction<
754 : ParallelComponent, Action, ReductionType>::registrar = // NOLINT
755 : Parallel::charmxx::register_func_with_charm<
756 : RegisterReductionAction<ParallelComponent, Action, ReductionType>>();
757 :
758 : // clang-tidy: redundant declaration
759 : template <typename Metavariables, typename Invokable, typename... Tags>
760 : bool Parallel::charmxx::RegisterPhaseChangeReduction<
761 : Metavariables, Invokable, Tags...>::registrar = // NOLINT
762 : Parallel::charmxx::register_func_with_charm<
763 : RegisterPhaseChangeReduction<Metavariables, Invokable, Tags...>>();
764 :
765 : // clang-tidy: redundant declaration
766 : template <typename Metavariables, typename GlobalCacheTag, typename Function,
767 : typename... Args>
768 : bool Parallel::charmxx::RegisterGlobalCacheMutate<
769 : Metavariables, GlobalCacheTag, Function,
770 : Args...>::registrar = // NOLINT
771 : Parallel::charmxx::register_func_with_charm<RegisterGlobalCacheMutate<
772 : Metavariables, GlobalCacheTag, Function, Args...>>();
773 :
774 : // clang-tidy: redundant declaration
775 : template <typename ParallelComponent, typename Action, typename PhaseIndex,
776 : typename DataBoxIndex>
777 : bool Parallel::charmxx::RegisterInvokeIterableAction<
778 : ParallelComponent, Action, PhaseIndex, DataBoxIndex>::registrar = // NOLINT
779 : Parallel::charmxx::register_func_with_charm<RegisterInvokeIterableAction<
780 : ParallelComponent, Action, PhaseIndex, DataBoxIndex>>();
781 :
782 : /// \cond
783 : class CkReductionMsg;
784 : /// \endcond
785 :
786 : namespace Parallel {
787 : namespace charmxx {
788 : /*!
789 : * \ingroup CharmExtensionsGroup
790 : * \brief The type of a function pointer to a Charm++ custom reduction function.
791 : */
792 1 : using ReducerFunctions = CkReductionMsg* (*)(int, CkReductionMsg**);
793 : /// \cond
794 : extern ReducerFunctions* charm_reducer_functions_list;
795 : extern size_t charm_reducer_functions_capacity;
796 : extern size_t charm_reducer_functions_size;
797 : extern std::unordered_map<size_t, CkReduction::reducerType>
798 : charm_reducer_functions;
799 : /// \endcond
800 :
801 : /*!
802 : * \ingroup CharmExtensionsGroup
803 : * \brief Class used for registering custom reduction function
804 : *
805 : * The static member variable is initialized before main is entered. This means
806 : * we are able to inject code into the beginning of the execution of an
807 : * executable by "using" the variable (casting to void counts) the function that
808 : * initializes the variable is called. We "use" `registrar` inside the
809 : * `Parallel::contribute_to_reduction` function.
810 : */
811 : template <ReducerFunctions>
812 1 : struct RegisterReducerFunction {
813 0 : static bool registrar;
814 : };
815 :
816 : /*!
817 : * \ingroup CharmExtensionsGroup
818 : * \brief Function that stores a function pointer to the custom reduction
819 : * function to be registered later.
820 : *
821 : * Used to initialize the `registrar` bool of `RegisterReducerFunction`. When
822 : * invoked it adds the function `F` of type `ReducerFunctions` to the list
823 : * `charm_reducer_functions_list`.
824 : *
825 : * \note The reason for not using a `std::vector<ReducerFunctions>` is that this
826 : * did not behave correctly when calling `push_back`. Specifically, the final
827 : * vector was always size 1, even though multiple elements were pushed back. The
828 : * reason for that behavior was never tracked down and so in the future it could
829 : * be possible to use a `std::vector`.
830 : */
831 : template <ReducerFunctions F>
832 1 : bool register_reducer_function() {
833 : #ifdef SPECTRE_CHARM_HAS_MAIN
834 : if (charm_reducer_functions_size >= charm_reducer_functions_capacity) {
835 : // clang-tidy: use gsl::owner (we don't use raw owning pointers unless
836 : // necessary)
837 : auto* const t = // NOLINT
838 : new ReducerFunctions[charm_reducer_functions_capacity + 10];
839 : for (size_t i = 0; i < charm_reducer_functions_capacity; ++i) {
840 : // clang-tidy: do not use pointer arithmetic
841 : t[i] = std::move(charm_reducer_functions_list[i]); // NOLINT
842 : }
843 : // clang-tidy: use gsl::owner (we don't use raw owning pointers unless
844 : // necessary)
845 : delete[] charm_reducer_functions_list; // NOLINT
846 : charm_reducer_functions_list = t;
847 : charm_reducer_functions_capacity += 10;
848 : }
849 : charm_reducer_functions_size++;
850 : // clang-tidy: do not use pointer arithmetic
851 : charm_reducer_functions_list[charm_reducer_functions_size - 1] = F; // NOLINT
852 : #endif // SPECTRE_CHARM_HAS_MAIN
853 : return true;
854 : }
855 : } // namespace charmxx
856 : } // namespace Parallel
857 :
858 : // clang-tidy: do not use pointer arithmetic
859 : template <Parallel::charmxx::ReducerFunctions F>
860 : bool Parallel::charmxx::RegisterReducerFunction<F>::registrar = // NOLINT
861 : Parallel::charmxx::register_reducer_function<F>();
|