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