MADNESS 0.10.1
worlddc.h
Go to the documentation of this file.
1/*
2 This file is part of MADNESS.
3
4 Copyright (C) 2007,2010 Oak Ridge National Laboratory
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 For more information please contact:
21
22 Robert J. Harrison
23 Oak Ridge National Laboratory
24 One Bethel Valley Road
25 P.O. Box 2008, MS-6367
26
27 email: harrisonrj@ornl.gov
28 tel: 865-241-3937
29 fax: 865-572-0680
30*/
31
32#ifndef MADNESS_WORLD_WORLDDC_H__INCLUDED
33#define MADNESS_WORLD_WORLDDC_H__INCLUDED
34
35/*!
36 \file worlddc.h
37 \brief Implements WorldContainer
38 \addtogroup worlddc
39 @{
40
41*/
42
43#include <algorithm>
44#include <cstring>
45#include <functional>
46#include <limits>
47#include <set>
48#include <map>
49#include <vector>
50#include <algorithm>
51#include <unordered_set>
52
53
59
60namespace madness
61{
62
63 template <typename keyT, typename valueT, typename hashfunT>
64 class WorldContainer;
65
66 template <typename keyT, typename valueT, typename hashfunT>
68
69 template <typename keyT, typename valueT, typename hashfunT>
71
72 template <typename keyT>
74
75 template <typename keyT>
77 {
78 public:
79 virtual std::size_t size() const = 0;
80 virtual void redistribute_phase1(const std::shared_ptr<WorldDCPmapInterface<keyT>> &newmap) = 0;
81 virtual void redistribute_phase2() = 0;
82 virtual void redistribute_phase3() = 0;
84 };
85
86 /// some introspection of how data is distributed
88 Distributed, ///< no replication of the container, the container is distributed over the world
89 RankReplicated, ///< replicate the container over all world ranks
90 NodeReplicated ///< replicate the container over all hosts (compute nodes), once per node,
91 ///< even if there are several ranks per node
92 };
93
94 template<typename T=long>
95 std::ostream& operator<<(std::ostream& os, const DistributionType type) {
96 if (type==DistributionType::Distributed) os << "Distributed";
97 if (type==DistributionType::RankReplicated) os << "RankReplicated";
98 if (type==DistributionType::NodeReplicated) os << "NodeReplicated";
99 return os;
100 }
101
102 template<typename T=long>
103 std::string to_string(const DistributionType type) {
104 std::stringstream ss; ss << type;
105 return ss.str();
106 }
107
108 template<typename T=long>
110 // to lower case
111 std::transform(type.begin(), type.end(), type.begin(), [](unsigned char c){ return std::tolower(c); });
112 if (type=="distributed") return Distributed;
113 if (type=="rankreplicated") return RankReplicated;
114 if (type=="nodereplicated") return NodeReplicated;
115 std::string msg="unknown distribution type:"+type;
116 MADNESS_EXCEPTION(msg.c_str(),1)
117 return Distributed;
118 }
119
120
121
122 /// Interface to be provided by any process map
123
124 /// NOTE: if the map is not distributed, but replicated, you must override the distribution_type() method.
125 /// \ingroup worlddc
126 template <typename keyT>
128 {
129 public:
131
132
133 private:
134 std::set<ptrT> ptrs;
135
136 public:
137 /// Maps key to processor
138
139 /// @param[in] key Key for container
140 /// @return Processor that logically owns the key
141 virtual ProcessID owner(const keyT &key) const = 0;
142
144
145 virtual void print() const {}
146
147 /// by default the map is distributed
149 {
150 return Distributed;
151 }
152
153 /// The one rank every key maps to on every process, or -1. Lets a cross-world
154 /// copy fetch from one owner instead of polling all ranks. Stronger than
155 /// WorldDCLocalPmap, whose owner is the calling rank.
156 virtual ProcessID single_owner() const
157 {
158 return -1;
159 }
160
161 /// Registers object for receipt of redistribute callbacks
162
163 /// @param[in] ptr Pointer to class derived from WorldDCRedistributedInterface
165 {
166 ptrs.insert(ptr);
167 }
168
169 /// Deregisters object for receipt of redistribute callbacks
170
171 /// @param[in] ptr Pointer to class derived from WorldDCRedistributedInterface
173 {
174 ptrs.erase(ptr);
175 }
176
177 /// Invoking this switches all registered objects from this process map to the new one
178
179 /// After invoking this routine all objects will be registered with the
180 /// new map and no objects will be registered in the current map.
181 /// @param[in] world The associated world
182 /// @param[in] newpmap The new process map
183 void redistribute(World &world, const std::shared_ptr<WorldDCPmapInterface<keyT>> &newpmap)
184 {
185 print_data_sizes(world, "before redistributing");
186 world.gop.fence();
187 for (typename std::set<ptrT>::iterator iter = ptrs.begin();
188 iter != ptrs.end();
189 ++iter)
190 {
191 (*iter)->redistribute_phase1(newpmap);
192 }
193 world.gop.fence();
194 for (typename std::set<ptrT>::iterator iter = ptrs.begin();
195 iter != ptrs.end();
196 ++iter)
197 {
198 (*iter)->redistribute_phase2();
199 newpmap->register_callback(*iter);
200 }
201 world.gop.fence();
202 for (typename std::set<ptrT>::iterator iter = ptrs.begin();
203 iter != ptrs.end();
204 ++iter)
205 {
206 (*iter)->redistribute_phase3();
207 }
208 world.gop.fence();
209 ptrs.clear();
210 newpmap->print_data_sizes(world, "after redistributing");
211 }
212
213 /// Counts global number of entries in all containers associated with this process map
214
215 /// Collective operation with global fence
216 std::size_t global_size(World &world) const
217 {
218 world.gop.fence();
219 std::size_t sum = local_size();
220 world.gop.sum(sum);
221 world.gop.fence();
222 return sum;
223 }
224
225 /// Counts local number of entries in all containers associated with this process map
226 std::size_t local_size() const
227 {
228 std::size_t sum = 0;
229 for (typename std::set<ptrT>::iterator iter = ptrs.begin(); iter != ptrs.end(); ++iter)
230 {
231 sum += (*iter)->size();
232 }
233 return sum;
234 }
235
236 /// Prints size info to std::cout
237
238 /// Collective operation with global fence
239 void print_data_sizes(World &world, const std::string msg = "") const
240 {
241 world.gop.fence();
242 std::size_t total = global_size(world);
243 std::vector<std::size_t> sizes(world.size());
244 sizes[world.rank()] = local_size();
245 world.gop.sum(&sizes[0], world.size());
246 if (world.rank() == 0)
247 {
248 madness::print("data distribution info", msg);
249 madness::print(" total: ", total);
250 std::cout << " procs: ";
251 for (int i = 0; i < world.size(); i++)
252 std::cout << sizes[i] << " ";
253 std::cout << std::endl;
254 }
255 world.gop.fence();
256 }
257 };
258
259 /// Default process map is "random" using madness::hash(key)
260
261 /// \ingroup worlddc
262 template <typename keyT, typename hashfunT = Hash<keyT>>
264 {
265 private:
266 const int nproc;
267 hashfunT hashfun;
268
269 public:
270 WorldDCDefaultPmap(World &world, const hashfunT &hf = hashfunT()) : nproc(world.mpi.nproc()),
271 hashfun(hf)
272 {
273 }
274
275 ProcessID owner(const keyT &key) const
276 {
277 if (nproc == 1)
278 return 0;
279 return hashfun(key) % nproc;
280 }
281 };
282
283 /// Local process map will always return the current process as owner
284
285 /// \ingroup worlddc
286 template <typename keyT, typename hashfunT = Hash<keyT>>
288 {
289 private:
291
292 public:
293 WorldDCLocalPmap(World &world) : me(world.rank()) {}
294 ProcessID owner(const keyT &key) const override
295 {
296 return me;
297 }
298
300 {
301 return RankReplicated;
302 }
303 };
304
305 /// Places every key on one fixed rank (all ranks agree on the owner).
306 ///
307 /// Moves a container's whole content onto one rank, so a cross-world copy is
308 /// a single fetch. Distribution type stays Distributed; see single_owner().
309 /// \ingroup worlddc
310 template <typename keyT>
312 {
313 private:
315
316 public:
318 ProcessID owner(const keyT & /*key*/) const override { return owner_; }
319 ProcessID single_owner() const override { return owner_; }
320 };
321
322 /// node-replicated map will return the lowest rank on the node as owner
323 ///
324 /// \ingroup worlddc
325 template <typename keyT, typename hashfunT = Hash<keyT>>
328
329 public:
330 /// ctor makes a map of all ranks to their owners (lowest rank on the host)
331 /// calls a fence
332 /// @param[in] world the associated world
333 explicit WorldDCNodeReplicatedPmap(World& world, const std::map<std::string,std::vector<long>> ranks_per_host) {
335 }
336
337 /// owner is the lowest rank on the node, same for all keys
338 ProcessID owner(const keyT &key) const override {
339 return myowner;
340 }
341
343 {
344 return NodeReplicated;
345 }
346 };
347
348 /// check distribution type of WorldContainer -- global communication
349 template <typename dcT>
351 {
352 // assume pmap distribution type is the correct result
353 World& world=dc.get_world();
354 auto result= dc.get_pmap()->distribution_type();
355
356 auto local_size=dc.size();
357 auto global_size=local_size;
358 world.gop.sum(global_size);
359
360 auto number_of_duplicates = [](const std::vector<hashT>& v) {
361 std::unordered_map<hashT, size_t> counts;
362 size_t duplicates = 0;
363 for (const auto& elem : v) {
364 if (++counts[elem] > 1) duplicates++;
365 }
366 return duplicates;
367 };
368
369 // collect all hash vales and determine the number of duplicates
370 std::vector<hashT> all_hashes(local_size);
371 const auto& hashfun=dc.get_hash();
372 int i=0;
373 for (auto it=dc.begin();it!=dc.end();++it,++i) all_hashes[i]=hashfun(it->first);
374 all_hashes=world.gop.concat0(all_hashes);
375 std::size_t ndup=number_of_duplicates(all_hashes);
376 world.gop.broadcast(ndup,0);
377 // print("rank, local, global, duplicates", world.rank(),local_size,global_size,ndup);
378
379 // consistency checks
380 if (result==Distributed) {
381 // all keys should exist only on one process
382 MADNESS_CHECK_THROW(ndup==0,"WorldDC inconsistent -- distributed has duplicates");
383 }
384 else if (result==RankReplicated) {
385 // all keys should exist on all processes
386 std::size_t nrank=world.size();
387 MADNESS_CHECK_THROW(global_size==nrank*local_size,"WorldDC inconsistent");
388 MADNESS_CHECK_THROW(ndup==local_size*(nrank-1),"WorldDC inconsistent - duplicates");
389 }
390 else if (result==NodeReplicated) {
391 // all keys should exist on all nodes, not on all ranks
392 auto ranks_per_host1=ranks_per_host(world);
393 std::vector<int> primary_ranks=primary_ranks_per_host(world,ranks_per_host1);
394 world.gop.broadcast_serializable(primary_ranks,0);
395 world.gop.fence();
396 print("primary_rank_per_host",primary_ranks);
397
398 std::size_t nnodes=primary_ranks.size();
399 bool is_primary=(std::find(primary_ranks.begin(),primary_ranks.end(),world.rank())!=primary_ranks.end());
400
401 if (is_primary) {
402 MADNESS_CHECK_THROW(global_size==(nnodes*local_size),"WorldDC inconsistent - global size");
403 MADNESS_CHECK_THROW(ndup==local_size*(nnodes-1),"WorldDC inconsistent - duplicates");
404 } else {
405 MADNESS_CHECK_THROW(local_size==0,"WorldDC inconsistent -- secondary");
406 }
407 }
408 return result;
409 }
410
411
412 /// Iterator for distributed container wraps the local iterator
413
414 /// \ingroup worlddc
415 template <class internal_iteratorT>
417 {
418 public:
419 typedef typename std::iterator_traits<internal_iteratorT>::iterator_category iterator_category;
420 typedef typename std::iterator_traits<internal_iteratorT>::value_type value_type;
421 typedef typename std::iterator_traits<internal_iteratorT>::difference_type difference_type;
422 typedef typename std::iterator_traits<internal_iteratorT>::pointer pointer;
423 typedef typename std::iterator_traits<internal_iteratorT>::reference reference;
424
425 private:
426 internal_iteratorT it; ///< Iterator from local container
427 // TODO: Convert this to a scoped pointer.
428 mutable value_type *value; ///< holds the remote values
429
430 public:
431 /// Default constructor makes a local uninitialized value
433 : it(), value(nullptr) {}
434
435 /// Initializes from a local iterator
436 explicit WorldContainerIterator(const internal_iteratorT &it)
437 : it(it), value(nullptr) {}
438
439 /// Initializes to cache a remote value
441 : it(), value(nullptr)
442 {
443 value = new value_type(v);
444 }
445
447 : it(), value(nullptr)
448 {
449 copy(other);
450 }
451
452 template <class iteratorT>
454 : it(), value(nullptr)
455 {
456 copy(other);
457 }
458
460 {
461 delete value;
462 }
463
464 /// Assignment
466 {
467 copy(other);
468 return *this;
469 }
470
471 /// Determines if two iterators are identical
472 bool operator==(const WorldContainerIterator &other) const
473 {
474 return (((!is_cached()) && (!other.is_cached())) && it == other.it) ||
475 ((is_cached() && other.is_cached()) && value->first == other.value->first);
476 }
477
478 /// Determines if two iterators are different
479 bool operator!=(const WorldContainerIterator &other) const
480 {
481 return !(*this == other);
482 }
483
484 /// Pre-increment of an iterator (i.e., ++it) --- \em local iterators only
485
486 /// Trying to increment a remote iterator will throw
488 {
490 ++it;
491 return *this;
492 }
493
495 {
498 ++it;
499 return result;
500 }
501
502 /// Iterators dereference to std::pair<const keyT,valueT>
504 {
505 return (is_cached() ? value : it.operator->());
506 }
507
508 /// Iterators dereference to std::pair<const keyT,valueT>
510 {
511 return (is_cached() ? *value : *it);
512 }
513
514 /// Private: (or should be) Returns iterator of internal container
515 const internal_iteratorT &get_internal_iterator() const
516 {
517 return it;
518 }
519
520 /// Returns true if this is non-local or cached value
521 bool is_cached() const
522 {
523 return value != nullptr;
524 }
525
526 template <typename Archive>
527 void serialize(const Archive &)
528 {
529 MADNESS_EXCEPTION("Serializing DC iterator ... why?", false);
530 }
531
532 private:
533 template <class iteratorT>
535
536 template <class iteratorT>
538 {
539 if (static_cast<const void *>(this) != static_cast<const void *>(&other))
540 {
541 delete value;
542 if (other.is_cached())
543 {
544 value = new value_type(*other.value);
545 it = internal_iteratorT();
546 }
547 else
548 {
549 it = other.it;
550 value = nullptr;
551 }
552 }
553 }
554 };
555
556 /// Internal implementation of distributed container to facilitate shallow copy
557
558 /// \ingroup worlddc
559 template <typename keyT, typename valueT, typename hashfunT>
561 : public WorldObject<WorldContainerImpl<keyT, valueT, hashfunT>>,
563#ifndef MADNESS_DISABLE_SHARED_FROM_THIS
564 ,
565 public std::enable_shared_from_this<WorldContainerImpl<keyT, valueT, hashfunT>>
566#endif // MADNESS_DISABLE_SHARED_FROM_THIS
567 {
568 public:
569 typedef typename std::pair<const keyT, valueT> pairT;
570 typedef const pairT const_pairT;
572
574
575 // typedef WorldObject< WorldContainerImpl<keyT, valueT, hashfunT> > worldobjT;
576
585
586 friend class WorldContainer<keyT, valueT, hashfunT>;
587
588 // template <typename containerT, typename datumT>
589 // inline
590 // static
591 // typename containerT::iterator replace(containerT& c, const datumT& d) {
592 // std::pair<typename containerT::iterator,bool> p = c.insert(d);
593 // if (!p.second) p.first->second = d.second; // Who's on first?
594 // return p.first;
595 // }
596
597 private:
598 WorldContainerImpl(); // Inhibit default constructor
599
600 std::shared_ptr<WorldDCPmapInterface<keyT>> pmap; ///< Function/class to map from keys to owning process
601 bool rank_replication_complete_ = false; ///< True if the last replicate() completed and no reset followed
602 const ProcessID me; ///< My MPI rank
603 internal_containerT local; ///< Locally owned data
604 std::vector<keyT> *move_list; ///< Tempoary used to record data that needs redistributing
605 std::map<ProcessID, std::vector<keyT>> coalesced_move_; ///< Temporary: keys to move, bucketed by destination (coalesced redistribute)
606
607 /// Handles find request
608 void find_handler(ProcessID requestor, const keyT &key, const RemoteReference<FutureImpl<iterator>> &ref)
609 {
610 internal_iteratorT r = local.find(key);
611 if (r == local.end())
612 {
613 // print("find_handler: failure:", key);
614 this->send(requestor, &implT::find_failure_handler, ref);
615 }
616 else
617 {
618 // print("find_handler: success:", key, r->first, r->second);
619 this->send(requestor, &implT::find_success_handler, ref, *r);
620 }
621 }
622
623 /// Handles successful find response
625 {
626 FutureImpl<iterator> *f = ref.get();
627 f->set(iterator(datum));
628 // print("find_success_handler: success:", datum.first, datum.second, f->get()->first, f->get()->second);
629 // Todo: Look at this again.
630 // ref.reset(); // Matching inc() in find() where ref was made
631 }
632
633 /// Handles unsuccessful find response
635 {
636 FutureImpl<iterator> *f = ref.get();
637 f->set(end());
638 // print("find_failure_handler");
639 // Todo: Look at this again.
640 // ref.reset(); // Matching inc() in find() where ref was made
641 }
642
643 /// Handles const find request
645 {
646 internal_iteratorT r = local.find(key);
647 if (r == local.end())
648 {
649 this->send(requestor, &implT::find_const_failure_handler, ref);
650 }
651 else
652 {
653 this->send(requestor, &implT::find_const_success_handler, ref, *r);
654 }
655 }
656
657 /// Handles successful const find response
659 {
660 FutureImpl<const_iterator> *f = ref.get();
661 f->set(const_iterator(datum));
662 }
663
664 /// Handles unsuccessful const find response
670
671 public:
673 const std::shared_ptr<WorldDCPmapInterface<keyT>> &pm,
674 const hashfunT &hf)
675 : WorldObject<WorldContainerImpl<keyT, valueT, hashfunT>>(world), pmap(pm), me(world.mpi.rank()), local(5011, hf)
676 {
677 pmap->register_callback(this);
678 }
679
681 {
682 pmap->deregister_callback(this);
683 }
684
685 const std::shared_ptr<WorldDCPmapInterface<keyT>> &get_pmap() const
686 {
687 return pmap;
688 }
689
690 std::shared_ptr<WorldDCPmapInterface<keyT>> &get_pmap()
691 {
692 return pmap;
693 }
694
696 {
698 pmap->deregister_callback(this);
699 pmap.reset(new WorldDCLocalPmap<keyT>(this->get_world()));
700 pmap->register_callback(this);
701 }
702
703 /// Replicates this WorldContainer on every ProcessID.
704 ///
705 /// This call is collective, and every rank must call it in the same order.
706 /// If no rank called clear(), reset the pmap, or redistributed after the
707 /// last completed call, this call sends no data. A requested fence still
708 /// occurs. This call does not reconcile replicas, so per-key changes must
709 /// be the same on every rank.
710 ///
711 /// A rank runs queued tasks while it waits in a broadcast. These tasks must
712 /// not change this container until the call returns. If a task erases a key
713 /// on the root, MADNESS_CHECK throws on that rank, and the other ranks wait.
714 void replicate(bool fence) {
715 World &world = this->get_world();
716
717 // clear() is local, so the ranks can disagree about the flag. All ranks
718 // take the fast path only if all ranks agree.
719 int complete = rank_replication_complete_ ? 1 : 0;
720 world.gop.min(complete);
721 if (complete) {
722 MADNESS_CHECK(pmap->distribution_type() == RankReplicated);
723 if (fence) world.gop.fence();
724 return;
725 }
726
727 pmap->deregister_callback(this);
729 pmap->register_callback(this);
730
733 if (fence) world.gop.fence();
734 }
735
736 /// Replicates this WorldContainer on all hosts, one ProcessID per host.
737 ///
738 /// The new pmap is host-local, not rank-local. This call always fences.
739 /// Queued tasks must not change this container until the call returns.
740 void replicate_on_hosts(bool fence) {
741 MADNESS_CHECK(fence);
743
744 /// print in rank-order
745// auto oprint = [&](World& world, auto &&... args) {
746// world.gop.fence();
747// for (int r=0; r<world.size(); ++r) {
748// if (r==world.rank()) {
749// std::cout << "rank " << world.rank() << ": ";
750// print(std::forward<decltype(args)>(args)...);
751// }
752// world.gop.fence();
753// }
754// };
755
756 World &world = this->get_world();
757
758 // find primary ranks per host (lowest rank on each host)
759 auto ranks_per_host1=ranks_per_host(world);
760 std::vector<int> primary_ranks=primary_ranks_per_host(world,ranks_per_host1);
761 world.gop.broadcast_serializable(primary_ranks,0);
762 world.gop.fence();
763
764// auto sizes =[&](std::string msg) {
765// world.gop.fence();
766// auto local_size=size();
767// auto global_size=local_size;
768// world.gop.sum(global_size);
769// oprint(world,"rank, local, global",msg, world.rank(),local_size,global_size);
770// world.gop.fence();
771// };
772
773 // change pmap to replicated
774 pmap->deregister_callback(this);
776 pmap->register_callback(this);
777
778 // shortcut: replace pmap and return
779 if (world.size()==1) {
780 // change pmap to node replicated
781 pmap->deregister_callback(this);
782 pmap.reset(new WorldDCNodeReplicatedPmap<keyT>(world,ranks_per_host1));
783 pmap->register_callback(this);
784 return;
785 }
786 world.gop.fence();
787
788 // get a list of all other ranks that are not primary
789 std::vector<int> secondary_ranks;
790 for (int r=0; r<world.size(); ++r) {
791 if (std::find(primary_ranks.begin(),primary_ranks.end(),r)==primary_ranks.end())
792 secondary_ranks.push_back(r);
793 }
794
795 // phase 1: for all ranks send data to the lowest rank on host
796
797 // step 1-2: send data to lowest rank on host (which will become the owner)
798 long myowner = lowest_rank_on_host_of_rank(ranks_per_host1, world.rank());
799 // oprint(world,"my owner, size:", myowner,size());
800 if (world.rank() != myowner) {
801 // send data to myowner
802 for (auto it = begin(); it != end(); ++it) {
803 keyT key = it->first;
804 valueT value = it->second;
805 this->send(myowner,&implT::insert,pairT(key,value));
806 // insert(pairT(key,value)); // this won't work with LocalPmap
807 }
808 // remove all local data after sending
809 // clear();
810 }
811 // need a fence here to make sure send is finished
812 world.gop.fence();
813 // sizes("after step 1, before clear");
814 // world.gop.fence();
815 if (world.rank()!=myowner) clear();
816 world.gop.fence();
817 // sizes("after step 1");
818
819 // change pmap to replicated
820 pmap->deregister_callback(this);
821 pmap.reset(new WorldDCNodeReplicatedPmap<keyT>(world,ranks_per_host1));
822 pmap->register_callback(this);
823
824 // check if this rank is in the primary list
825 bool i_am_in_primary_list=world.rank()==myowner;
826 if (i_am_in_primary_list) {
827
828 // step 2-1: create a world with only the primary ranks and replicate there (see test_world.cc)
829
830 SafeMPI::Group primary_group = world.mpi.comm().Get_group().Incl(primary_ranks.size(), &primary_ranks[0]);
831 SafeMPI::Intracomm comm_primary = world.mpi.comm().Create(primary_group);
832 // step 2-2: replicate in the primary world
833 {
834 World world_primary(comm_primary);
835 // auto ranks_per_host1=ranks_per_host(world_primary);
836 // if (world_primary.rank()==0) {
837 // print("host/rank map in primary world:");
838 // for (auto& p : ranks_per_host1) print(p.first, p.second);
839 // }
840
841 world_primary.gop.fence(); // this fence seems necessary, why??
842 do_replicate(world_primary);
843 world_primary.gop.fence();
844 }
845 } else {
846 // need this to avoid deadlock in MPI_Comm_create (why??)
847 SafeMPI::Group secondary_group = world.mpi.comm().Get_group().Incl(secondary_ranks.size(), &secondary_ranks[0]);
848 SafeMPI::Intracomm comm_secondary = world.mpi.comm().Create(secondary_group);
849 }
850
851 // phase 3: done
852 if (fence) world.gop.fence();
853 // validate_distribution_type(*this);
854 }
855
857 // Received entries go to a side buffer, not into local, so each
858 // rank broadcasts only the entries it held on entry and every entry
859 // is sent exactly once. Inserting as we go would make later roots
860 // re-broadcast what they received from earlier ones.
861 std::vector<pairT> received;
862 for (ProcessID rank = 0; rank < world.size(); rank++)
863 {
864 if (rank == world.rank())
865 {
866 std::size_t sz = size();
867 world.gop.broadcast_serializable(sz, rank);
868
869 for (auto it = begin(); it != end(); ++it)
870 {
871 keyT key = it->first;
872 valueT value = it->second;
873 world.gop.broadcast_serializable(key, rank);
874 world.gop.broadcast_serializable(value, rank);
875 }
876 }
877 else
878 {
879 size_t sz = 0;
880 world.gop.broadcast_serializable(sz, rank);
881 received.reserve(received.size() + sz);
882 for (size_t i = 0; i < sz; i++)
883 {
884 keyT key{};
885 valueT value{};
886 world.gop.broadcast_serializable(key, rank);
887 world.gop.broadcast_serializable(value, rank);
888 received.emplace_back(std::move(key), std::move(value));
889 }
890 }
891 }
892 for (auto& datum : received)
893 insert(datum);
894 }
895
896 const hashfunT &get_hash() const { return local.get_hash(); }
897
898 bool is_local(const keyT &key) const
899 {
900 return owner(key) == me;
901 }
902
903 ProcessID owner(const keyT &key) const
904 {
905 return pmap->owner(key);
906 }
907
908 bool probe(const keyT &key) const
909 {
910 ProcessID dest = owner(key);
911 if (dest == me)
912 return local.find(key) != local.end();
913 else
914 return false;
915 }
916
917 std::size_t size() const
918 {
919 return local.size();
920 }
921
922 void insert(const pairT &datum)
923 {
924 ProcessID dest = owner(datum.first);
925 if (dest == me)
926 {
927 // Was using iterator ... try accessor ?????
928 accessor acc;
929 // N.B. key might already exist if want to simply replace
930 [[maybe_unused]] auto inserted = local.insert(acc, datum.first);
931 acc->second = datum.second;
932 }
933 else
934 {
935 // Must be send (not task) for sequential consistency (and relies on single-threaded remote server)
936 this->send(dest, &implT::insert, datum);
937 }
938 }
939
940 bool insert_acc(accessor &acc, const keyT &key)
941 {
942 MADNESS_ASSERT(owner(key) == me);
943 return local.insert(acc, key);
944 }
945
946 bool insert_const_acc(const_accessor &acc, const keyT &key)
947 {
948 MADNESS_ASSERT(owner(key) == me);
949 return local.insert(acc, key);
950 }
951
952 /// AM target of the coalesced redistribute: bulk-insert boxes this rank owns
953 /// under the already-adopted new pmap. Keys are disjoint from those this rank
954 /// is concurrently erasing (their new owner != me), so per-bucket locking
955 /// suffices. See redistribute_coalesced_phase2.
956 void insert_batch(const std::vector<pairT> &boxes)
957 {
958 for (const pairT &kv : boxes)
959 {
960 accessor acc;
961 [[maybe_unused]] auto inserted = local.insert(acc, kv.first);
962 acc->second = kv.second;
963 }
964 }
965
966 void clear()
967 {
969 local.clear();
970 }
971
972 void erase(const keyT &key)
973 {
974 ProcessID dest = owner(key);
975 if (dest == me)
976 {
977 [[maybe_unused]] auto erased = local.try_erase(key);
978 MADNESS_ASSERT(erased);
979 }
980 else
981 {
982 void (implT::*eraser)(const keyT &) = &implT::erase;
983 this->send(dest, eraser, key);
984 }
985 }
986
987 template <typename InIter>
988 void erase(InIter it)
989 {
990 MADNESS_ASSERT(!it.is_cached());
991 MADNESS_ASSERT(it != end());
992 erase(it->first);
993 }
994
995 template <typename InIter>
996 void erase(InIter first, InIter last)
997 {
998 InIter it = first;
999 do
1000 {
1001 first++;
1002 erase(it->first);
1003 it = first;
1004 } while (first != last);
1005 }
1006
1008 {
1009 return iterator(local.begin());
1010 }
1011
1013 {
1014 return const_iterator(local.begin());
1015 }
1016
1018 {
1019 return iterator(local.end());
1020 }
1021
1023 {
1024 return const_iterator(local.end());
1025 }
1026
1028 {
1029 ProcessID dest = owner(key);
1030 if (dest == me)
1031 {
1032 return Future<const_iterator>(const_iterator(local.find(key)));
1033 }
1034 else
1035 {
1037 this->send(dest, &implT::find_const_handler, me, key, result.remote_ref(this->get_world()));
1038 return result;
1039 }
1040 }
1041
1043 {
1044 ProcessID dest = owner(key);
1045 if (dest == me)
1046 {
1047 return Future<iterator>(iterator(local.find(key)));
1048 }
1049 else
1050 {
1051 Future<iterator> result;
1052 this->send(dest, &implT::find_handler, me, key, result.remote_ref(this->get_world()));
1053 return result;
1054 }
1055 }
1056
1057 bool find(accessor &acc, const keyT &key)
1058 {
1059 if (owner(key) != me)
1060 return false;
1061 return local.find(acc, key);
1062 }
1063
1064 bool find(const_accessor &acc, const keyT &key) const
1065 {
1066 if (owner(key) != me)
1067 return false;
1068 return local.find(acc, key);
1069 }
1070
1071 // Used to forward call to item member function
1072 template <typename memfunT>
1073 MEMFUN_RETURNT(memfunT)
1074 itemfun(const keyT &key, memfunT memfun)
1075 {
1076 accessor acc;
1077 // N.B. key may already exist, this is just to ensure lock is held by acc
1078 [[maybe_unused]] auto inserted = local.insert(acc, key);
1079 return (acc->second.*memfun)();
1080 }
1081
1082 // Used to forward call to item member function
1083 template <typename memfunT, typename arg1T>
1084 MEMFUN_RETURNT(memfunT)
1085 itemfun(const keyT &key, memfunT memfun, const arg1T &arg1)
1086 {
1087 accessor acc;
1088 // N.B. key may already exist, this is just to ensure lock is held by acc
1089 [[maybe_unused]] auto inserted = local.insert(acc, key);
1090 return (acc->second.*memfun)(arg1);
1091 }
1092
1093 // Used to forward call to item member function
1094 template <typename memfunT, typename arg1T, typename arg2T>
1095 MEMFUN_RETURNT(memfunT)
1096 itemfun(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2)
1097 {
1098 accessor acc;
1099 // N.B. key may already exist, this is just to ensure lock is held by acc
1100 [[maybe_unused]] auto inserted = local.insert(acc, key);
1101 return (acc->second.*memfun)(arg1, arg2);
1102 }
1103
1104 // Used to forward call to item member function
1105 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T>
1106 MEMFUN_RETURNT(memfunT)
1107 itemfun(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3)
1108 {
1109 accessor acc;
1110 // N.B. key may already exist, this is just to ensure lock is held by acc
1111 [[maybe_unused]] auto inserted = local.insert(acc, key);
1112 return (acc->second.*memfun)(arg1, arg2, arg3);
1113 }
1114
1115 // Used to forward call to item member function
1116 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T>
1117 MEMFUN_RETURNT(memfunT)
1118 itemfun(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4)
1119 {
1120 accessor acc;
1121 // N.B. key may already exist, this is just to ensure lock is held by acc
1122 [[maybe_unused]] auto inserted = local.insert(acc, key);
1123 return (acc->second.*memfun)(arg1, arg2, arg3, arg4);
1124 }
1125
1126 // Used to forward call to item member function
1127 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T, typename arg5T>
1128 MEMFUN_RETURNT(memfunT)
1129 itemfun(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5)
1130 {
1131 accessor acc;
1132 // N.B. key may already exist, this is just to ensure lock is held by acc
1133 [[maybe_unused]] auto inserted = local.insert(acc, key);
1134 return (acc->second.*memfun)(arg1, arg2, arg3, arg4, arg5);
1135 }
1136
1137 // Used to forward call to item member function
1138 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T, typename arg5T, typename arg6T>
1139 MEMFUN_RETURNT(memfunT)
1140 itemfun(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6)
1141 {
1142 accessor acc;
1143 // N.B. key may already exist, this is just to ensure lock is held by acc
1144 [[maybe_unused]] auto inserted = local.insert(acc, key);
1145 return (acc->second.*memfun)(arg1, arg2, arg3, arg4, arg5, arg6);
1146 }
1147
1148 // Used to forward call to item member function
1149 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T, typename arg5T, typename arg6T, typename arg7T>
1150 MEMFUN_RETURNT(memfunT)
1151 itemfun(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3,
1152 const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const arg7T &arg7)
1153 {
1154 accessor acc;
1155 // N.B. key may already exist, this is just to ensure lock is held by acc
1156 [[maybe_unused]] auto inserted = local.insert(acc, key);
1157 return (acc->second.*memfun)(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
1158 }
1159
1160 // First phase of redistributions changes pmap and makes list of stuff to move
1161 void redistribute_phase1(const std::shared_ptr<WorldDCPmapInterface<keyT>> &newpmap)
1162 {
1164 pmap = newpmap;
1165 move_list = new std::vector<keyT>();
1166 for (typename internal_containerT::iterator iter = local.begin(); iter != local.end(); ++iter)
1167 {
1168 if (owner(iter->first) != me)
1169 move_list->push_back(iter->first);
1170 }
1171 }
1172
1173 struct P2Op
1174 {
1178 P2Op(const P2Op &p) : impl(p.impl) {}
1180 {
1181 typename internal_containerT::iterator iter = impl->local.find(*iterator);
1182 MADNESS_ASSERT(iter != impl->local.end());
1183
1184 // impl->insert(*iter);
1185 impl->task(impl->owner(*iterator), &implT::insert, *iter);
1186
1187 impl->local.erase(iter); // delete local copy of the data
1188 return true;
1189 }
1190 };
1191
1192 // Second phase moves data
1194 {
1195 this->get_world().taskq.for_each(typename P2Op::rangeT(move_list->begin(), move_list->end()), P2Op(this));
1196 // std::vector<keyT>& mvlist = *move_list;
1197 // for (unsigned int i=0; i<move_list->size(); ++i) {
1198 // typename internal_containerT::iterator iter = local.find(mvlist[i]);
1199 // MADNESS_ASSERT(iter != local.end());
1200 // insert(*iter);
1201 // local.erase(iter);
1202 // }
1203 // delete move_list;
1204 }
1205
1206 // Third phase cleans up
1208 {
1209 delete move_list;
1210 }
1211
1212 // --- Coalesced redistribute: like redistribute_phase1/2, but phase2 sends ONE
1213 // bulk AM per (destination, chunk) instead of one AM per box. The caller owns
1214 // the fences: fence, phase1 on all containers, fence, phase2, fence. The middle
1215 // fence is REQUIRED -- phase1 iterates the ConcurrentHashMap and needs a
1216 // quiescent window; phase2 tolerates concurrent insert_batch (disjoint keys).
1217
1218 /// phase1: adopt newpmap (callback swap as in replicate()) and bucket the keys
1219 /// to move by destination. Quiescent window required.
1220 void redistribute_coalesced_phase1(const std::shared_ptr<WorldDCPmapInterface<keyT>> &newpmap)
1221 {
1223 pmap->deregister_callback(this);
1224 pmap = newpmap;
1225 pmap->register_callback(this);
1226 coalesced_move_.clear();
1227 for (typename internal_containerT::iterator iter = local.begin(); iter != local.end(); ++iter)
1228 {
1229 ProcessID d = owner(iter->first); // uses the new pmap
1230 if (d != me)
1231 coalesced_move_[d].push_back(iter->first);
1232 }
1233 }
1234
1235 /// phase2: per destination, chunk the key list (at most cap_boxes per chunk),
1236 /// erase each box after copying it into the batch, send one insert_batch AM
1237 /// per chunk.
1238 void redistribute_coalesced_phase2(std::size_t cap_boxes, bool rotate)
1239 {
1240 if (cap_boxes == 0) cap_boxes = 1;
1241 std::vector<ProcessID> dsts;
1242 dsts.reserve(coalesced_move_.size());
1243 for (const auto &kv : coalesced_move_) dsts.push_back(kv.first);
1244 // rotate: destinations > me first, so ranks don't all hammer dst 0 at once
1245 if (rotate)
1246 std::stable_partition(dsts.begin(), dsts.end(),
1247 [this](ProcessID d) { return d > me; });
1248 for (ProcessID d : dsts)
1249 {
1250 const std::vector<keyT> &keys = coalesced_move_[d];
1251 std::vector<pairT> batch;
1252 batch.reserve(std::min(cap_boxes, keys.size()));
1253 for (std::size_t i = 0; i < keys.size(); ++i)
1254 {
1255 typename internal_containerT::iterator iter = local.find(keys[i]);
1256 if (iter != local.end())
1257 {
1258 batch.push_back(pairT(keys[i], iter->second));
1259 local.erase(iter); // delete local copy of the data
1260 }
1261 if (batch.size() >= cap_boxes || i + 1 == keys.size())
1262 {
1263 if (!batch.empty())
1264 {
1265 this->task(d, &implT::insert_batch, batch); // one bulk AM per chunk
1266 batch.clear();
1267 }
1268 }
1269 }
1270 }
1271 coalesced_move_.clear();
1272 }
1273 };
1274
1275 /// Makes a distributed container with specified attributes
1276
1277 /// \ingroup worlddc
1278 ///
1279 /// There is no communication or syncronization associated with
1280 /// making a new container, but every process must invoke the
1281 /// constructor for each container in the same order. This is so
1282 /// that we can assign each container a unique ID without any
1283 /// communication. Since remotely invoked operations may start
1284 /// happening before local construction, messages on not yet
1285 /// constructed containers are buffered pending construction.
1286 ///
1287 /// Similarly, when a container is destroyed, the actual
1288 /// destruction is deferred until a synchronization point
1289 /// (world.gop.fence()) in order to eliminate the need to fence
1290 /// before destroying every container.
1291 ///
1292 /// The distribution of data between processes is controlled by
1293 /// the process map (Pmap) class. The default is uniform
1294 /// hashing based upon a strong (Bob Jenkins, lookup3) bytewise
1295 /// hash of the key.
1296 ///
1297 /// All operations, including constructors and destructors, are
1298 /// non-blocking and return immediately. If communication occurs
1299 /// it is asynchronous, otherwise operations are local.
1300 template <typename keyT, typename valueT, typename hashfunT = Hash<keyT>>
1302 {
1303 public:
1304 // access keyT and valueT types for serialization
1308 typedef typename implT::pairT pairT;
1309 typedef typename implT::iterator iterator;
1311 typedef typename implT::accessor accessor;
1315
1316 private:
1317 std::shared_ptr<implT> p;
1318
1319 inline void check_initialized() const
1320 {
1322 }
1323
1324 public:
1325 /// Makes an uninitialized container (no communication)
1326
1327 /// The container is useless until assigned to from a fully
1328 /// constructed container. There is no need to worry about
1329 /// default constructors being executed in order.
1331 : p()
1332 {
1333 }
1334
1335 /// Makes an initialized, empty container with default data distribution (no communication)
1336
1337 /// A unique ID is associated with every distributed container
1338 /// within a world. In order to avoid synchronization when
1339 /// making a container, we have to assume that all processes
1340 /// execute this constructor in the same order (does not apply
1341 /// to the non-initializing, default constructor).
1342 WorldContainer(World &world, bool do_pending = true, const hashfunT &hf = hashfunT())
1343 : p(new implT(world,
1344 std::shared_ptr<WorldDCPmapInterface<keyT>>(new WorldDCDefaultPmap<keyT, hashfunT>(world, hf)),
1345 hf))
1346 {
1347 if (do_pending)
1348 p->process_pending();
1349 }
1350
1351 /// Makes an initialized, empty container (no communication)
1352
1353 /// A unique ID is associated with every distributed container
1354 /// within a world. In order to avoid synchronization when
1355 /// making a container, we have to assume that all processes
1356 /// execute this constructor in the same order (does not apply
1357 /// to the non-initializing, default constructor).
1359 const std::shared_ptr<WorldDCPmapInterface<keyT>> &pmap,
1360 bool do_pending = true,
1361 const hashfunT &hf = hashfunT())
1362 : p(new implT(world, pmap, hf))
1363 {
1364 if (do_pending)
1365 p->process_pending();
1366 }
1367
1368 /// Copy constructor is shallow (no communication)
1369
1370 /// The copy refers to exactly the same container as other
1371 /// which must be initialized.
1373 : p(other.p)
1374 {
1376 }
1377
1378 /// Assignment is shallow (no communication)
1379
1380 /// The copy refers to exactly the same container as other
1381 /// which must be initialized.
1383 {
1384 if (this != &other)
1385 {
1386 other.check_initialized();
1387 p = other.p;
1388 }
1389 return *this;
1390 }
1391
1392 /// return the way data is distributed
1394 if (!p) MADNESS_EXCEPTION("Uninitialized container", false);
1395 return p->get_pmap()->distribution_type();
1396 }
1397
1398 bool is_distributed() const {
1400 }
1401
1402 bool is_replicated() const {
1404 }
1405
1406 bool is_host_replicated() const {
1408 }
1409
1410 /// Returns the world associated with this container
1412 {
1414 return p->get_world();
1415 }
1416
1417 std::shared_ptr<WorldDCPmapInterface<keyT>> &get_impl()
1418 {
1420 return p;
1421 }
1422
1423 /// Replicates this WorldContainer on all ProcessIDs.
1424 ///
1425 /// This call is collective. Queued tasks must not change this container
1426 /// until the call returns. See WorldContainerImpl::replicate().
1427 void replicate(bool fence = true)
1428 {
1429 p->replicate(fence);
1430 }
1431
1432 /// replicates this WorldContainer on all hosts (one PID per host)
1433 void replicate_on_hosts(bool fence = true)
1434 {
1435 p->replicate_on_hosts(fence);
1436 }
1437
1438 /// Coalesced redistribute, phase 1: adopt newpmap, bucket the move list.
1439 /// Caller fences before (quiescent window).
1440 void redistribute_coalesced_phase1(const std::shared_ptr<WorldDCPmapInterface<keyT>> &newpmap)
1441 {
1443 p->redistribute_coalesced_phase1(newpmap);
1444 }
1445
1446 /// Coalesced redistribute, phase 2: one bulk AM per (destination, chunk of at
1447 /// most cap_boxes), erase-after-copy. Caller fences after; rotate staggers
1448 /// destinations to reduce incast.
1449 void redistribute_coalesced_phase2(std::size_t cap_boxes, bool rotate = true)
1450 {
1452 p->redistribute_coalesced_phase2(cap_boxes, rotate);
1453 }
1454
1455 /// Inserts/replaces key+value pair (non-blocking communication if key not local)
1456 void replace(const pairT &datum)
1457 {
1459 p->insert(datum);
1460 }
1461
1462 /// Inserts/replaces key+value pair (non-blocking communication if key not local)
1463 void replace(const keyT &key, const valueT &value)
1464 {
1465 replace(pairT(key, value));
1466 }
1467
1468 /// Write access to LOCAL value by key. Returns true if found, false otherwise (always false for remote).
1469 bool find(accessor &acc, const keyT &key)
1470 {
1472 return p->find(acc, key);
1473 }
1474
1475 /// Read access to LOCAL value by key. Returns true if found, false otherwise (always false for remote).
1476 bool find(const_accessor &acc, const keyT &key) const
1477 {
1479 return p->find(acc, key);
1480 }
1481
1482 /// Write access to LOCAL value by key. Returns true if inserted, false if already exists (throws if remote)
1483 bool insert(accessor &acc, const keyT &key)
1484 {
1486 return p->insert_acc(acc, key);
1487 }
1488
1489 /// Read access to LOCAL value by key. Returns true if inserted, false if already exists (throws if remote)
1490 bool insert(const_accessor &acc, const keyT &key)
1491 {
1493 return p->insert_acc(acc, key);
1494 }
1495
1496 /// Inserts pairs (non-blocking communication if key(s) not local)
1497 template <typename input_iterator>
1498 void replace(input_iterator &start, input_iterator &end)
1499 {
1501 using std::placeholders::_1;
1502 std::for_each(start, end, std::bind(this, std::mem_fn(&containerT::insert), _1));
1503 }
1504
1505 /// Returns true if local data is immediately available (no communication)
1506 bool probe(const keyT &key) const
1507 {
1509 return p->probe(key);
1510 }
1511
1512 /// Returns processor that logically owns key (no communication)
1513
1514 /// Local remapping may have changed its physical location, but all
1515 /// operations should forward correctly.
1516 inline ProcessID owner(const keyT &key) const
1517 {
1519 return p->owner(key);
1520 }
1521
1522 /// Returns true if the key maps to the local processor (no communication)
1523 bool is_local(const keyT &key) const
1524 {
1526 return p->is_local(key);
1527 }
1528
1529 /// Returns a future iterator (non-blocking communication if key not local)
1530
1531 /// Like an std::map an iterator "points" to an std::pair<const keyT,valueT>.
1532 ///
1533 /// Refer to Future for info on how to avoid blocking.
1535 { //
1537 return p->find(key);
1538 }
1539
1540 /// Returns a future iterator (non-blocking communication if key not local)
1541
1542 /// Like an std::map an iterator "points" to an std::pair<const keyT,valueT>.
1543 ///
1544 /// Refer to Future for info on how to avoid blocking.
1546 {
1548 return const_cast<const implT *>(p.get())->find(key);
1549 }
1550
1551 /// Returns an iterator to the beginning of the \em local data (no communication)
1553 {
1555 return p->begin();
1556 }
1557
1558 /// Returns an iterator to the beginning of the \em local data (no communication)
1560 {
1562 return const_cast<const implT *>(p.get())->begin();
1563 }
1564
1565 /// Returns an iterator past the end of the \em local data (no communication)
1567 {
1569 return p->end();
1570 }
1571
1572 /// Returns an iterator past the end of the \em local data (no communication)
1574 {
1576 return const_cast<const implT *>(p.get())->end();
1577 }
1578
1579 /// Erases entry from container (non-blocking comm if remote)
1580
1581 /// Missing keys are quietly ignored.
1582 ///
1583 /// Note that erasing an entry may invalidate iterators on the
1584 /// remote end. This is just the same as what happens when
1585 /// using STL iterators on an STL container in a sequential
1586 /// algorithm.
1587 void erase(const keyT &key)
1588 {
1590 p->erase(key);
1591 }
1592
1593 /// Erases entry corresponding to \em local iterator (no communication)
1594 void erase(const iterator &it)
1595 {
1597 p->erase(it);
1598 }
1599
1600 /// Erases range defined by \em local iterators (no communication)
1601 void erase(const iterator &start, const iterator &finish)
1602 {
1604 p->erase(start, finish);
1605 }
1606
1607 /// Clears all \em local data (no communication)
1608
1609 /// Invalidates all iterators
1610 void clear()
1611 {
1613 p->clear();
1614 }
1615
1616 /// Returns the number of \em local entries (no communication)
1617 std::size_t size() const
1618 {
1620 return p->size();
1621 }
1622
1623 /// Returns shared pointer to the process mapping
1624 inline const std::shared_ptr<WorldDCPmapInterface<keyT>> &get_pmap() const
1625 {
1627 return p->get_pmap();
1628 }
1629
1630 /// Returns shared pointer to the process mapping
1632 {
1633 p->reset_pmap_to_local();
1634 }
1635
1636 /// Returns a reference to the hashing functor
1637 const hashfunT &get_hash() const
1638 {
1640 return p->get_hash();
1641 }
1642
1643 /// Process pending messages
1644
1645 /// If the constructor was given \c do_pending=false then you
1646 /// \em must invoke this routine in order to process both
1647 /// prior and future messages.
1648 inline void process_pending()
1649 {
1651 p->process_pending();
1652 }
1653
1654 /// Sends message "resultT memfun()" to item (non-blocking comm if remote)
1655
1656 /// If item does not exist it is made with the default constructor.
1657 ///
1658 /// Future arguments must be ready for remote messages.
1659 ///
1660 /// Returns a future result (Future<void> may be ignored).
1661 ///
1662 /// The method executes with a write lock on the item.
1663 template <typename memfunT>
1664 Future<MEMFUN_RETURNT(memfunT)>
1665 send(const keyT &key, memfunT memfun)
1666 {
1668 MEMFUN_RETURNT(memfunT)
1669 (implT::*itemfun)(const keyT &, memfunT) = &implT::template itemfun<memfunT>;
1670 return p->send(owner(key), itemfun, key, memfun);
1671 }
1672
1673 /// Sends message "resultT memfun(arg1T)" to item (non-blocking comm if remote)
1674
1675 /// If item does not exist it is made with the default constructor.
1676 ///
1677 /// Future arguments must be ready for remote messages.
1678 ///
1679 /// Returns a future result (Future<void> may be ignored).
1680 ///
1681 /// The method executes with a write lock on the item.
1682 template <typename memfunT, typename arg1T>
1684 send(const keyT &key, const memfunT &memfun, const arg1T &arg1)
1685 {
1687 // To work around bug in g++ 4.3.* use static cast as alternative mechanism to force type deduction
1688 MEMFUN_RETURNT(memfunT)
1689 (implT::*itemfun)(const keyT &, memfunT, const arg1T &) = &implT::template itemfun<memfunT, arg1T>;
1690 return p->send(owner(key), itemfun, key, memfun, arg1);
1691 /*return p->send(owner(key),
1692 static_cast<MEMFUN_RETURNT(memfunT)(implT::*)(const keyT&, memfunT, const arg1T&)>(&implT:: template itemfun<memfunT,arg1T>),
1693 key, memfun, arg1);*/
1694 }
1695
1696 /// Sends message "resultT memfun(arg1T,arg2T)" to item (non-blocking comm if remote)
1697
1698 /// If item does not exist it is made with the default constructor.
1699 ///
1700 /// Future arguments must be ready for both local and remote messages.
1701 ///
1702 /// Returns a future result (Future<void> may be ignored).
1703 ///
1704 /// The method executes with a write lock on the item.
1705 template <typename memfunT, typename arg1T, typename arg2T>
1707 send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2)
1708 {
1710 // To work around bug in g++ 4.3.* use static cast as alternative mechanism to force type deduction
1711 MEMFUN_RETURNT(memfunT)
1712 (implT::*itemfun)(const keyT &, memfunT, const arg1T &, const arg2T &) = &implT::template itemfun<memfunT, arg1T, arg2T>;
1713 return p->send(owner(key), itemfun, key, memfun, arg1, arg2);
1714 /*return p->send(owner(key),
1715 static_cast<MEMFUN_RETURNT(memfunT)(implT::*)(const keyT&, memfunT, const arg1T&, const arg2T&)>(&implT:: template itemfun<memfunT,arg1T,arg2T>), key, memfun, arg1, arg2);*/
1716 }
1717
1718 /// Sends message "resultT memfun(arg1T,arg2T,arg3T)" to item (non-blocking comm if remote)
1719
1720 /// If item does not exist it is made with the default constructor.
1721 ///
1722 /// Future arguments must be ready for both local and remote messages.
1723 ///
1724 /// Returns a future result (Future<void> may be ignored).
1725 ///
1726 /// The method executes with a write lock on the item.
1727 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T>
1729 send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3)
1730 {
1732 MEMFUN_RETURNT(memfunT)
1733 (implT::*itemfun)(const keyT &, memfunT, const arg1T &, const arg2T &, const arg3T &) = &implT::template itemfun<memfunT, arg1T, arg2T, arg3T>;
1734 return p->send(owner(key), itemfun, key, memfun, arg1, arg2, arg3);
1735 }
1736
1737 /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T)" to item (non-blocking comm if remote)
1738
1739 /// If item does not exist it is made with the default constructor.
1740 ///
1741 /// Future arguments must be ready for both local and remote messages.
1742 ///
1743 /// Returns a future result (Future<void> may be ignored).
1744 ///
1745 /// The method executes with a write lock on the item.
1746 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T>
1748 send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4)
1749 {
1751 MEMFUN_RETURNT(memfunT)
1752 (implT::*itemfun)(const keyT &, memfunT, const arg1T &, const arg2T &, const arg3T &, const arg4T &) = &implT::template itemfun<memfunT, arg1T, arg2T, arg3T, arg4T>;
1753 return p->send(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4);
1754 }
1755
1756 /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T)" to item (non-blocking comm if remote)
1757
1758 /// If item does not exist it is made with the default constructor.
1759 ///
1760 /// Future arguments must be ready for both local and remote messages.
1761 ///
1762 /// Returns a future result (Future<void> may be ignored).
1763 ///
1764 /// The method executes with a write lock on the item.
1765 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T, typename arg5T>
1767 send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5)
1768 {
1770 MEMFUN_RETURNT(memfunT)
1771 (implT::*itemfun)(const keyT &, memfunT, const arg1T &, const arg2T &, const arg3T &, const arg4T &, const arg5T &) = &implT::template itemfun<memfunT, arg1T, arg2T, arg3T, arg4T, arg5T>;
1772 return p->send(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, arg5);
1773 }
1774
1775 /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T)" to item (non-blocking comm if remote)
1776
1777 /// If item does not exist it is made with the default constructor.
1778 ///
1779 /// Future arguments must be ready for both local and remote messages.
1780 ///
1781 /// Returns a future result (Future<void> may be ignored).
1782 ///
1783 /// The method executes with a write lock on the item.
1784 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T, typename arg5T, typename arg6T>
1786 send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6)
1787 {
1789 MEMFUN_RETURNT(memfunT)
1790 (implT::*itemfun)(const keyT &, memfunT, const arg1T &, const arg2T &, const arg3T &, const arg4T &, const arg5T &, const arg6T &) = &implT::template itemfun<memfunT, arg1T, arg2T, arg3T, arg4T, arg5T, arg6T>;
1791 return p->send(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, arg5, arg6);
1792 }
1793
1794 /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T,arg7T)" to item (non-blocking comm if remote)
1795
1796 /// If item does not exist it is made with the default constructor.
1797 ///
1798 /// Future arguments must be ready for both local and remote messages.
1799 ///
1800 /// Returns a future result (Future<void> may be ignored).
1801 ///
1802 /// The method executes with a write lock on the item.
1803 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T, typename arg5T, typename arg6T, typename arg7T>
1805 send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4,
1806 const arg5T &arg5, const arg6T &arg6, const arg7T &arg7)
1807 {
1809 MEMFUN_RETURNT(memfunT)
1810 (implT::*itemfun)(const keyT &, memfunT, const arg1T &, const arg2T &, const arg3T &, const arg4T &, const arg5T &, const arg6T &, const arg7T &) = &implT::template itemfun<memfunT, arg1T, arg2T, arg3T, arg4T, arg5T, arg6T, arg7T>;
1811 return p->send(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
1812 }
1813
1814 /// Sends message "resultT memfun() const" to item (non-blocking comm if remote)
1815
1816 /// The method executes with a write lock on the item.
1817 template <typename memfunT>
1819 send(const keyT &key, memfunT memfun) const
1820 {
1821 return const_cast<containerT *>(this)->send(key, memfun);
1822 }
1823
1824 /// Sends message "resultT memfun(arg1T) const" to item (non-blocking comm if remote)
1825
1826 /// The method executes with a write lock on the item.
1827 template <typename memfunT, typename arg1T>
1829 send(const keyT &key, memfunT memfun, const arg1T &arg1) const
1830 {
1831 return const_cast<containerT *>(this)->send(key, memfun, arg1);
1832 }
1833
1834 /// Sends message "resultT memfun(arg1T,arg2T) const" to item (non-blocking comm if remote)
1835
1836 /// The method executes with a write lock on the item.
1837 template <typename memfunT, typename arg1T, typename arg2T>
1839 send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2) const
1840 {
1841 return const_cast<containerT *>(this)->send(key, memfun, arg1, arg2);
1842 }
1843
1844 /// Sends message "resultT memfun(arg1T,arg2T,arg3T) const" to item (non-blocking comm if remote)
1845
1846 /// The method executes with a write lock on the item.
1847 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T>
1849 send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3) const
1850 {
1851 return const_cast<containerT *>(this)->send(key, memfun, arg1, arg2, arg3);
1852 }
1853
1854 /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T) const" to item (non-blocking comm if remote)
1855
1856 /// The method executes with a write lock on the item.
1857 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T>
1859 send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4) const
1860 {
1861 return const_cast<containerT *>(this)->send(key, memfun, arg1, arg2, arg3, arg4);
1862 }
1863
1864 /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T) const" to item (non-blocking comm if remote)
1865
1866 /// The method executes with a write lock on the item.
1867 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T, typename arg5T>
1869 send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5) const
1870 {
1871 return const_cast<containerT *>(this)->send(key, memfun, arg1, arg2, arg3, arg4, arg5);
1872 }
1873
1874 /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T) const" to item (non-blocking comm if remote)
1875
1876 /// The method executes with a write lock on the item.
1877 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T, typename arg5T, typename arg6T>
1879 send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3,
1880 const arg4T &arg4, const arg5T &arg5, const arg6T &arg6) const
1881 {
1882 return const_cast<containerT *>(this)->send(key, memfun, arg1, arg2, arg3, arg4, arg5, arg6);
1883 }
1884
1885 /// Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T,arg7T) const" to item (non-blocking comm if remote)
1886
1887 /// The method executes with a write lock on the item.
1888 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T, typename arg5T, typename arg6T, typename arg7T>
1890 send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3,
1891 const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const arg7T &arg7) const
1892 {
1893 return const_cast<containerT *>(this)->send(key, memfun, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
1894 }
1895
1896 /// Adds task "resultT memfun()" in process owning item (non-blocking comm if remote)
1897
1898 /// If item does not exist it is made with the default constructor.
1899 ///
1900 /// Future arguments for local tasks can generate dependencies, but for remote
1901 /// tasks all futures must be ready.
1902 ///
1903 /// Returns a future result (Future<void> may be ignored).
1904 ///
1905 /// The method executes with a write lock on the item.
1906 template <typename memfunT>
1908 task(const keyT &key, memfunT memfun, const TaskAttributes &attr = TaskAttributes())
1909 {
1911 MEMFUN_RETURNT(memfunT)
1912 (implT::*itemfun)(const keyT &, memfunT) = &implT::template itemfun<memfunT>;
1913 return p->task(owner(key), itemfun, key, memfun, attr);
1914 }
1915
1916 /// Adds task "resultT memfun(arg1T)" in process owning item (non-blocking comm if remote)
1917
1918 /// If item does not exist it is made with the default constructor.
1919 ///
1920 /// Future arguments for local tasks can generate dependencies, but for remote
1921 /// tasks all futures must be ready.
1922 ///
1923 /// Returns a future result (Future<void> may be ignored).
1924 ///
1925 /// The method executes with a write lock on the item.
1926 template <typename memfunT, typename arg1T>
1928 task(const keyT &key, memfunT memfun, const arg1T &arg1, const TaskAttributes &attr = TaskAttributes())
1929 {
1931 typedef REMFUTURE(arg1T) a1T;
1932 MEMFUN_RETURNT(memfunT)
1933 (implT::*itemfun)(const keyT &, memfunT, const a1T &) = &implT::template itemfun<memfunT, a1T>;
1934 return p->task(owner(key), itemfun, key, memfun, arg1, attr);
1935 }
1936
1937 /// Adds task "resultT memfun(arg1T,arg2T)" in process owning item (non-blocking comm if remote)
1938
1939 /// If item does not exist it is made with the default constructor.
1940 ///
1941 /// Future arguments for local tasks can generate dependencies, but for remote
1942 /// tasks all futures must be ready.
1943 ///
1944 /// Returns a future result (Future<void> may be ignored).
1945 ///
1946 /// The method executes with a write lock on the item.
1947 template <typename memfunT, typename arg1T, typename arg2T>
1949 task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const TaskAttributes &attr = TaskAttributes())
1950 {
1952 typedef REMFUTURE(arg1T) a1T;
1953 typedef REMFUTURE(arg2T) a2T;
1954 MEMFUN_RETURNT(memfunT)
1955 (implT::*itemfun)(const keyT &, memfunT, const a1T &, const a2T &) = &implT::template itemfun<memfunT, a1T, a2T>;
1956 return p->task(owner(key), itemfun, key, memfun, arg1, arg2, attr);
1957 }
1958
1959 /// Adds task "resultT memfun(arg1T,arg2T,arg3T)" in process owning item (non-blocking comm if remote)
1960
1961 /// If item does not exist it is made with the default constructor.
1962 ///
1963 /// Future arguments for local tasks can generate dependencies, but for remote
1964 /// tasks all futures must be ready.
1965 ///
1966 /// Returns a future result (Future<void> may be ignored).
1967 ///
1968 /// The method executes with a write lock on the item.
1969 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T>
1971 task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const TaskAttributes &attr = TaskAttributes())
1972 {
1974 typedef REMFUTURE(arg1T) a1T;
1975 typedef REMFUTURE(arg2T) a2T;
1976 typedef REMFUTURE(arg3T) a3T;
1977 MEMFUN_RETURNT(memfunT)
1978 (implT::*itemfun)(const keyT &, memfunT, const a1T &, const a2T &, const a3T &) = &implT::template itemfun<memfunT, a1T, a2T, a3T>;
1979 return p->task(owner(key), itemfun, key, memfun, arg1, arg2, arg3, attr);
1980 }
1981
1982 /// Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T)" in process owning item (non-blocking comm if remote)
1983
1984 /// If item does not exist it is made with the default constructor.
1985 ///
1986 /// Future arguments for local tasks can generate dependencies, but for remote
1987 /// tasks all futures must be ready.
1988 ///
1989 /// Returns a future result (Future<void> may be ignored).
1990 ///
1991 /// The method executes with a write lock on the item.
1992 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T>
1994 task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const TaskAttributes &attr = TaskAttributes())
1995 {
1997 typedef REMFUTURE(arg1T) a1T;
1998 typedef REMFUTURE(arg2T) a2T;
1999 typedef REMFUTURE(arg3T) a3T;
2000 typedef REMFUTURE(arg4T) a4T;
2001 MEMFUN_RETURNT(memfunT)
2002 (implT::*itemfun)(const keyT &, memfunT, const a1T &, const a2T &, const a3T &, const a4T &) = &implT::template itemfun<memfunT, a1T, a2T, a3T, a4T>;
2003 return p->task(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, attr);
2004 }
2005
2006 /// Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T)" in process owning item (non-blocking comm if remote)
2007
2008 /// If item does not exist it is made with the default constructor.
2009 ///
2010 /// Future arguments for local tasks can generate dependencies, but for remote
2011 /// tasks all futures must be ready.
2012 ///
2013 /// Returns a future result (Future<void> may be ignored).
2014 ///
2015 /// The method executes with a write lock on the item.
2016 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T, typename arg5T>
2018 task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const TaskAttributes &attr = TaskAttributes())
2019 {
2021 typedef REMFUTURE(arg1T) a1T;
2022 typedef REMFUTURE(arg2T) a2T;
2023 typedef REMFUTURE(arg3T) a3T;
2024 typedef REMFUTURE(arg4T) a4T;
2025 typedef REMFUTURE(arg5T) a5T;
2026 MEMFUN_RETURNT(memfunT)
2027 (implT::*itemfun)(const keyT &, memfunT, const a1T &, const a2T &, const a3T &, const a4T &, const a5T &) = &implT::template itemfun<memfunT, a1T, a2T, a3T, a4T, a5T>;
2028 return p->task(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, arg5, attr);
2029 }
2030
2031 /// Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T)" in process owning item (non-blocking comm if remote)
2032
2033 /// If item does not exist it is made with the default constructor.
2034 ///
2035 /// Future arguments for local tasks can generate dependencies, but for remote
2036 /// tasks all futures must be ready.
2037 ///
2038 /// Returns a future result (Future<void> may be ignored).
2039 ///
2040 /// The method executes with a write lock on the item.
2041 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T, typename arg5T, typename arg6T>
2043 task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const TaskAttributes &attr = TaskAttributes())
2044 {
2046 typedef REMFUTURE(arg1T) a1T;
2047 typedef REMFUTURE(arg2T) a2T;
2048 typedef REMFUTURE(arg3T) a3T;
2049 typedef REMFUTURE(arg4T) a4T;
2050 typedef REMFUTURE(arg5T) a5T;
2051 typedef REMFUTURE(arg6T) a6T;
2052 MEMFUN_RETURNT(memfunT)
2053 (implT::*itemfun)(const keyT &, memfunT, const a1T &, const a2T &, const a3T &, const a4T &, const a5T &, const a6T &) = &implT::template itemfun<memfunT, a1T, a2T, a3T, a4T, a5T, a6T>;
2054 return p->task(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, arg5, arg6, attr);
2055 }
2056
2057 /// Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T,arg7T)" in process owning item (non-blocking comm if remote)
2058
2059 /// If item does not exist it is made with the default constructor.
2060 ///
2061 /// Future arguments for local tasks can generate dependencies, but for remote
2062 /// tasks all futures must be ready.
2063 ///
2064 /// Returns a future result (Future<void> may be ignored).
2065 ///
2066 /// The method executes with a write lock on the item.
2067 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T, typename arg5T, typename arg6T, typename arg7T>
2069 task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const arg7T &arg7, const TaskAttributes &attr = TaskAttributes())
2070 {
2072 typedef REMFUTURE(arg1T) a1T;
2073 typedef REMFUTURE(arg2T) a2T;
2074 typedef REMFUTURE(arg3T) a3T;
2075 typedef REMFUTURE(arg4T) a4T;
2076 typedef REMFUTURE(arg5T) a5T;
2077 typedef REMFUTURE(arg6T) a6T;
2078 typedef REMFUTURE(arg7T) a7T;
2079 MEMFUN_RETURNT(memfunT)
2080 (implT::*itemfun)(const keyT &, memfunT, const a1T &, const a2T &, const a3T &, const a4T &, const a5T &, const a6T &, const a7T &) = &implT::template itemfun<memfunT, a1T, a2T, a3T, a4T, a5T, a6T, a7T>;
2081 return p->task(owner(key), itemfun, key, memfun, arg1, arg2, arg3, arg4, arg5, arg6, arg7, attr);
2082 }
2083
2084 /// Adds task "resultT memfun() const" in process owning item (non-blocking comm if remote)
2085
2086 /// The method executes with a write lock on the item.
2087 template <typename memfunT>
2089 task(const keyT &key, memfunT memfun, const TaskAttributes &attr = TaskAttributes()) const
2090 {
2091 return const_cast<containerT *>(this)->task(key, memfun, attr);
2092 }
2093
2094 /// Adds task "resultT memfun(arg1T) const" in process owning item (non-blocking comm if remote)
2095
2096 /// The method executes with a write lock on the item.
2097 template <typename memfunT, typename arg1T>
2099 task(const keyT &key, memfunT memfun, const arg1T &arg1, const TaskAttributes &attr = TaskAttributes()) const
2100 {
2101 return const_cast<containerT *>(this)->task(key, memfun, arg1, attr);
2102 }
2103
2104 /// Adds task "resultT memfun(arg1T,arg2T) const" in process owning item (non-blocking comm if remote)
2105
2106 /// The method executes with a write lock on the item.
2107 template <typename memfunT, typename arg1T, typename arg2T>
2109 task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const TaskAttributes &attr = TaskAttributes()) const
2110 {
2111 return const_cast<containerT *>(this)->task(key, memfun, arg1, arg2, attr);
2112 }
2113
2114 /// Adds task "resultT memfun(arg1T,arg2T,arg3T) const" in process owning item (non-blocking comm if remote)
2115
2116 /// The method executes with a write lock on the item.
2117 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T>
2119 task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const TaskAttributes &attr = TaskAttributes()) const
2120 {
2121 return const_cast<containerT *>(this)->task(key, memfun, arg1, arg2, arg3, attr);
2122 }
2123
2124 /// Adds task "resultT memfun(arg1T,arg2T,arg3T, arg4T) const" in process owning item (non-blocking comm if remote)
2125
2126 /// The method executes with a write lock on the item.
2127 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T>
2129 task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const TaskAttributes &attr = TaskAttributes()) const
2130 {
2131 return const_cast<containerT *>(this)->task(key, memfun, arg1, arg2, arg3, arg4, attr);
2132 }
2133
2134 /// Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T) const" in process owning item (non-blocking comm if remote)
2135
2136 /// The method executes with a write lock on the item.
2137 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T, typename arg5T>
2139 task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const TaskAttributes &attr = TaskAttributes()) const
2140 {
2141 return const_cast<containerT *>(this)->task(key, memfun, arg1, arg2, arg3, arg4, arg5, attr);
2142 }
2143
2144 /// Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T) const" in process owning item (non-blocking comm if remote)
2145
2146 /// The method executes with a write lock on the item.
2147 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T, typename arg5T, typename arg6T>
2149 task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const TaskAttributes &attr = TaskAttributes()) const
2150 {
2151 return const_cast<containerT *>(this)->task(key, memfun, arg1, arg2, arg3, arg4, arg5, arg6, attr);
2152 }
2153
2154 /// Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T,arg7T) const" in process owning item (non-blocking comm if remote)
2155
2156 /// The method executes with a write lock on the item.
2157 template <typename memfunT, typename arg1T, typename arg2T, typename arg3T, typename arg4T, typename arg5T, typename arg6T, typename arg7T>
2159 task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const arg7T &arg7, const TaskAttributes &attr = TaskAttributes()) const
2160 {
2161 return const_cast<containerT *>(this)->task(key, memfun, arg1, arg2, arg3, arg4, arg5, arg6, arg7, attr);
2162 }
2163
2164 /// (de)Serialize --- *Local* data only to/from anything *except* Buffer*Archive and Parallel*Archive
2165
2166 /// Advisable for *you* to fence before and after this to ensure consistency
2167 template <typename Archive>
2168 void serialize(const Archive &ar)
2169 {
2170 //
2171 // !! If you change the format of this stream make sure that
2172 // !! the parallel in/out archive below is compatible
2173 //
2174 const long magic = 5881828; // Sitar Indian restaurant in Knoxville
2175 unsigned long count = 0;
2177
2178 if (Archive::is_output_archive)
2179 {
2180 ar & magic;
2181 for (iterator it = begin(); it != end(); ++it)
2182 count++;
2183 ar & count;
2184 for (iterator it = begin(); it != end(); ++it)
2185 ar &*it;
2186 }
2187 else
2188 {
2189 long cookie = 0l;
2190 ar & cookie;
2191 MADNESS_ASSERT(cookie == magic);
2192 ar & count;
2193 while (count--)
2194 {
2195 pairT datum;
2196 ar & datum;
2197 replace(datum);
2198 }
2199 }
2200 }
2201
2202 /// (de)Serialize --- !! ONLY for purpose of interprocess communication
2203
2204 /// This just writes/reads the unique id to/from the Buffer*Archive.
2206 {
2208 ar &static_cast<WorldObject<implT> *>(p.get());
2209 }
2210
2211 /// (de)Serialize --- !! ONLY for purpose of interprocess communication
2212
2213 /// This just writes/reads the unique id to/from the Buffer*Archive.
2215 {
2216 WorldObject<implT> *ptr = nullptr;
2217 ar & ptr;
2218 MADNESS_ASSERT(ptr);
2219
2220#ifdef MADNESS_DISABLE_SHARED_FROM_THIS
2221 p.reset(static_cast<implT *>(ptr), [](implT *p_) -> void{});
2222#else
2223 p = static_cast<implT *>(ptr)->shared_from_this();
2224#endif // MADNESS_DISABLE_SHARED_FROM_THIS
2225 }
2226
2227 /// Returns the associated unique id ... must be initialized
2228 const uniqueidT &id() const
2229 {
2231 return p->id();
2232 }
2233
2234 /// Destructor passes ownership of implementation to world for deferred cleanup
2236 {
2237 detail::deferred_cleanup(p->get_world(), p);
2238 }
2239
2241 };
2242
2243 /// Swaps the content of two WorldContainer objects. It should be called on all nodes.
2244
2245 /// \ingroup worlddc
2246 template <typename keyT, typename valueT, typename hashfunT>
2248 {
2249 std::swap(dc0.p, dc1.p);
2250 }
2251
2252
2253 namespace archive
2254 {
2255
2256 /// Write container to parallel archive
2257
2258 /// specialization for parallel serialization of a WorldContainer:
2259 /// all threads on each process serialize some values into a buffer, which gets concatenated
2260 /// and finally serialized to localarchive (aka VectorOutputArchive).
2261 template <class keyT, class valueT>
2263 {
2265 {
2266 using localarchiveT = VectorOutputArchive;
2267 const long magic = -5881828; // Sitar Indian restaurant in Knoxville (negative to indicate parallel!)
2268 typedef WorldContainer<keyT, valueT> dcT;
2269 using const_iterator = typename dcT::const_iterator;
2270 int count = t.size(); // Must be INT for MPI and NOT const since we'll do a global sum eventually
2271
2272 // Strategy:
2273 // 1. Serialize local data to a buffer in parallel over threads
2274 // a) Compute the size of the buffer needed by each task
2275 // b) Sum sizes and allocate the buffer of exact sizes needed for all threads
2276 // c) Serialize the data into the buffer in parallel over threads
2277 // 2. Gather all buffers to process 0
2278
2279 World *world = ar.get_world();
2280 world->gop.fence(); // Global fence here
2281
2282 class op_inspector : public TaskInterface
2283 {
2284 const_iterator start, end;
2285 size_t &size;
2286
2287 public:
2288 op_inspector(const_iterator start, const_iterator end, size_t &size)
2289 : start(start), end(end), size(size) {}
2290
2291 using TaskInterface::run;
2292
2293 void run(World &world) override
2294 {
2296 for (const_iterator it = start; it != end; ++it)
2297 bo &*it;
2298 size = bo.size();
2299 }
2300 };
2301
2302 class op_executor : public TaskInterface
2303 {
2304 const_iterator start, end;
2305 unsigned char *buf;
2306 const size_t size;
2307
2308 public:
2309 op_executor(const_iterator start, const_iterator end, unsigned char *buf, size_t size)
2310 : start(start), end(end), buf(buf), size(size) {}
2311
2312 using TaskInterface::run;
2313
2314 void run(World &world) override
2315 {
2316 BufferOutputArchive bo(buf, size);
2317 for (const_iterator it = start; it != end; ++it)
2318 {
2319 bo &*it;
2320 }
2321 MADNESS_CHECK(size == bo.size());
2322 }
2323 };
2324
2325 // No need for LOCAL fence here since only master thread is busy
2326 double wall0 = wall_time();
2327 const size_t ntasks = std::min(size_t(count), std::max(size_t(1), ThreadPool::size()));
2328 size_t local_size = 0;
2329 double wall1 = wall0;
2330 unsigned char* buf = 0;
2331 if (ntasks > 0)
2332 {
2333 const size_t max_items_per_task = (std::max(1, count) - 1) / ntasks + 1;
2334 // Compute the size of the buffer needed by each task
2335 std::vector<const_iterator> starts(ntasks), ends(ntasks);
2336 std::vector<size_t> local_sizes(ntasks);
2337 const_iterator start = t.begin();
2338 size_t nleft = count;
2339 for (size_t taskid = 0; taskid < ntasks; taskid++)
2340 {
2341 const_iterator end = start;
2342 if (taskid == (ntasks - 1))
2343 {
2344 end = t.end();
2345 }
2346 else
2347 {
2348 size_t nitems = std::min(max_items_per_task, nleft);
2349 std::advance(end, max_items_per_task);
2350 nleft -= nitems;
2351 }
2352 starts[taskid] = start;
2353 ends[taskid] = end;
2354 world->taskq.add(new op_inspector(start, end, local_sizes[taskid])); // Be sure to pass iterators by value!!
2355 start = end;
2356 }
2357 world->taskq.fence(); // just need LOCAL fence
2358 wall1 = wall_time();
2359 // if (world->rank() == 0)
2360 // printf("time in op_inspector: %8.4fs\n", wall1 - wall0);
2361 wall0 = wall1;
2362
2363 // total size over all threads
2364 for (size_t taskid = 0; taskid < ntasks; taskid++)
2365 {
2366 local_size += local_sizes[taskid];
2367 // print("taskid",taskid,"size",local_sizes[taskid]);
2368 }
2369
2370 // Allocate the buffer for all threads
2371 buf = new unsigned char[local_size];
2372
2373 // Now execute the serialization
2374 size_t offset = 0;
2375 for (size_t taskid = 0; taskid < ntasks; taskid++)
2376 {
2377 world->taskq.add(new op_executor(starts[taskid], ends[taskid], buf + offset, local_sizes[taskid]));
2378 offset += local_sizes[taskid];
2379 }
2380 world->taskq.fence(); // just need LOCAL fence
2381
2382 wall1 = wall_time();
2383 // if (world->rank() == 0)
2384 // printf("time in op_executor: %8.4fs\n", wall1 - wall0);
2385 wall0 = wall1;
2386 }
2387 // VERify that the serialization worked!!
2388 // {
2389 // BufferInputArchive bi(buf, local_size);
2390 // for (int item=0; item<count; item++) {
2391 // std::pair<keyT, valueT> datum;
2392 // bi & datum;
2393 // print("deserializing",datum.first);
2394 // }
2395 // }
2396
2397 // Gather all per-rank buffers to process 0, then write them out
2398 // contiguously. A single rank's buffer (local_size) and the grand
2399 // total can both exceed INT_MAX, so all sizes/offsets are size_t and
2400 // the point-to-point transfers are chunked to stay within the INT_MAX
2401 // limit of one MPI message. (The old code used int sizes/offsets and a
2402 // single MPI_Gatherv, which overflowed to a negative size and threw
2403 // std::bad_alloc once a function's serialized container exceeded 2 GiB.)
2404 world->gop.sum(count); // just need total number of elements
2405
2406 // largest payload sent through a single SafeMPI message (leave headroom
2407 // below INT_MAX for any per-message overhead), mirroring worldrmi.
2408 constexpr std::size_t max_msg =
2409 static_cast<std::size_t>(std::numeric_limits<int>::max()) - (std::size_t(1) << 20);
2410 const Tag gather_tag = world->mpi.unique_tag();
2411
2412 if (world->rank() == 0)
2413 {
2414 // collect every rank's buffer size (size_t, no truncation)
2415 std::vector<std::size_t> sizes(world->size(), 0);
2416 sizes[0] = local_size;
2417 for (ProcessID p = 1; p < world->size(); ++p)
2418 world->mpi.Recv(sizes[p], p, gather_tag);
2419
2420 std::size_t total_size = 0;
2421 for (ProcessID p = 0; p < world->size(); ++p)
2422 total_size += sizes[p];
2423
2424 unsigned char *all_data = new unsigned char[total_size];
2425
2426 // rank 0's own buffer goes first
2427 if (local_size > 0)
2428 std::memcpy(all_data, buf, local_size);
2429 std::size_t offset = local_size;
2430
2431 // then receive each remote rank's buffer, chunked to <= max_msg
2432 for (ProcessID p = 1; p < world->size(); ++p)
2433 {
2434 std::size_t received = 0;
2435 while (received < sizes[p])
2436 {
2437 const std::size_t n = std::min(sizes[p] - received, max_msg);
2438 world->mpi.Recv(all_data + offset + received, long(n), p, gather_tag);
2439 received += n;
2440 }
2441 offset += sizes[p];
2442 }
2443 delete[] buf;
2444
2445 auto &localar = ar.local_archive();
2446 localar & magic & 1; // 1 client
2447 // localar & t;
2449 localar & -magic &(unsigned long)(count);
2450 localar.store(all_data, total_size);
2452
2453 delete[] all_data;
2454 }
2455 else
2456 {
2457 // tell rank 0 how many bytes we hold, then send them chunked
2458 world->mpi.Send(local_size, 0, gather_tag);
2459 std::size_t sent = 0;
2460 while (sent < local_size)
2461 {
2462 const std::size_t n = std::min(local_size - sent, max_msg);
2463 world->mpi.Send(buf + sent, long(n), 0, gather_tag);
2464 sent += n;
2465 }
2466 delete[] buf;
2467 }
2468 world->gop.fence();
2469 }
2470 };
2471
2472 /// Write container to parallel archive with optional fence
2473
2474 /// \ingroup worlddc
2475 /// Each node (process) is served by a designated IO node.
2476 /// The IO node has a binary local file archive to which is
2477 /// first written a cookie and the number of servers. The IO
2478 /// node then loops thru all of its clients and in turn tells
2479 /// each to write its data over an MPI stream, which is copied
2480 /// directly to the output file. The stream contents are then
2481 /// cookie, no. of clients, foreach client (usual sequential archive).
2482 ///
2483 /// If ar.dofence() is true (default) fence is invoked before and
2484 /// after the IO. The fence is optional but it is of course
2485 /// necessary to be sure that all updates have completed
2486 /// before doing IO, and that all IO has completed before
2487 /// subsequent modifications. Also, there is always at least
2488 /// some synchronization between a client and its IO server.
2489 template <class keyT, class valueT, class localarchiveT>
2491 {
2493 {
2494 const long magic = -5881828; // Sitar Indian restaurant in Knoxville (negative to indicate parallel!)
2495 typedef WorldContainer<keyT, valueT> dcT;
2496 // typedef typename dcT::const_iterator iterator; // unused?
2497 typedef typename dcT::pairT pairT;
2498 World *world = ar.get_world();
2499 Tag tag = world->mpi.unique_tag();
2500 ProcessID me = world->rank();
2501 if (ar.dofence())
2502 world->gop.fence();
2503 if (ar.is_io_node())
2504 {
2505 auto &localar = ar.local_archive();
2506 localar & magic & ar.num_io_clients();
2507 for (ProcessID p = 0; p < world->size(); ++p)
2508 {
2509 if (p == me)
2510 {
2511 localar & t;
2512 }
2513 else if (ar.io_node(p) == me)
2514 {
2515 world->mpi.Send(int(1), p, tag); // Tell client to start sending
2517 long cookie = 0l;
2518 unsigned long count = 0ul;
2519
2521
2522 source & cookie & count;
2523 localar & cookie & count;
2524 while (count--)
2525 {
2526 pairT datum;
2527 source & datum;
2528 localar & datum;
2529 }
2530
2532 }
2533 }
2534 }
2535 else
2536 {
2537 ProcessID p = ar.my_io_node();
2538 int flag;
2539 world->mpi.Recv(flag, p, tag);
2540 MPIOutputArchive dest(*world, p);
2541 dest & t;
2542 dest.flush();
2543 }
2544 if (ar.dofence())
2545 world->gop.fence();
2546 }
2547 };
2548
2549 template <class keyT, class valueT, class localarchiveT>
2551 {
2552 /// Read container from parallel archive
2553
2554 /// \ingroup worlddc
2555 /// See store method above for format of file content.
2556 /// !!! We presently ASSUME that the number of writers and readers are
2557 /// the same. This is frustrating but not a show stopper since you
2558 /// can always run a separate job to copy to a different number.
2559 ///
2560 /// The IO node simply reads all data and inserts entries.
2562 {
2563 const long magic = -5881828; // Sitar Indian restaurant in Knoxville (negative to indicate parallel!)
2564 // typedef WorldContainer<keyT,valueT> dcT; // unused
2565 // typedef typename dcT::iterator iterator; // unused
2566 // typedef typename dcT::pairT pairT; // unused
2567 World *world = ar.get_world();
2568 if (ar.dofence())
2569 world->gop.fence();
2570 if (ar.is_io_node())
2571 {
2572 long cookie = 0l;
2573 int nclient = 0;
2574 auto &localar = ar.local_archive();
2575 localar & cookie & nclient;
2576 MADNESS_CHECK(cookie == magic);
2577 while (nclient--)
2578 {
2579 localar & t;
2580 }
2581 }
2582 if (ar.dofence())
2583 world->gop.fence();
2584 }
2585 };
2586 }
2587
2588}
2589
2590///@}
2591
2592#endif // MADNESS_WORLD_WORLDDC_H__INCLUDED
Definition safempi.h:435
Wrapper around MPI_Comm. Has a shallow copy constructor; use Create(Get_group()) for deep copy.
Definition safempi.h:497
int unique_tag()
Returns a unique tag for temporary use (1023<tag<4095).
Definition safempi.h:837
Definition worldhashmap.h:396
Hash_private::HashAccessor< const hashT, entryT::READLOCK > const_accessor
Definition worldhashmap.h:405
Hash_private::HashAccessor< hashT, entryT::WRITELOCK > accessor
Definition worldhashmap.h:404
Hash_private::HashIterator< const hashT > const_iterator
Definition worldhashmap.h:403
Hash_private::HashIterator< hashT > iterator
Definition worldhashmap.h:402
Implements the functionality of futures.
Definition future.h:75
A future is a possibly yet unevaluated value.
Definition future.h:370
remote_refT remote_ref(World &world) const
Returns a structure used to pass references to another process.
Definition future.h:672
Range, vaguely a la Intel TBB, to encapsulate a random-access, STL-like start and end iterator with c...
Definition range.h:64
iteratorT iterator
Alias for the iterator type.
Definition range.h:71
Simple structure used to manage references/pointers to remote instances.
Definition worldref.h:394
Contains attributes of a task.
Definition thread.h:330
All world tasks must be derived from this public interface.
Definition taskfn.h:69
virtual void run(const TaskThreadEnv &env)
Override this method to implement a multi-threaded task.
Definition world_task_queue.cc:45
static std::size_t size()
Returns the number of threads in the pool.
Definition thread.h:1460
Internal implementation of distributed container to facilitate shallow copy.
Definition worlddc.h:567
void erase(const keyT &key)
Definition worlddc.h:972
WorldContainerIterator< internal_iteratorT > iterator
Definition worlddc.h:582
const hashfunT & get_hash() const
Definition worlddc.h:896
bool find(const_accessor &acc, const keyT &key) const
Definition worlddc.h:1064
internal_containerT::accessor accessor
Definition worlddc.h:579
void find_handler(ProcessID requestor, const keyT &key, const RemoteReference< FutureImpl< iterator > > &ref)
Handles find request.
Definition worlddc.h:608
bool probe(const keyT &key) const
Definition worlddc.h:908
void find_success_handler(const RemoteReference< FutureImpl< iterator > > &ref, const pairT &datum)
Handles successful find response.
Definition worlddc.h:624
std::pair< const keyT, valueT > pairT
Definition worlddc.h:569
bool insert_const_acc(const_accessor &acc, const keyT &key)
Definition worlddc.h:946
void redistribute_coalesced_phase1(const std::shared_ptr< WorldDCPmapInterface< keyT > > &newpmap)
Definition worlddc.h:1220
WorldContainerIterator< internal_const_iteratorT > const_iteratorT
Definition worlddc.h:583
bool find(accessor &acc, const keyT &key)
Definition worlddc.h:1057
void redistribute_phase2()
Definition worlddc.h:1193
void insert(const pairT &datum)
Definition worlddc.h:922
WorldContainerIterator< internal_iteratorT > iteratorT
Definition worlddc.h:581
void clear()
Definition worlddc.h:966
bool insert_acc(accessor &acc, const keyT &key)
Definition worlddc.h:940
void find_const_failure_handler(const RemoteReference< FutureImpl< const_iterator > > &ref)
Handles unsuccessful const find response.
Definition worlddc.h:665
Future< iterator > find(const keyT &key)
Definition worlddc.h:1042
WorldContainerImpl(World &world, const std::shared_ptr< WorldDCPmapInterface< keyT > > &pm, const hashfunT &hf)
Definition worlddc.h:672
void redistribute_coalesced_phase2(std::size_t cap_boxes, bool rotate)
Definition worlddc.h:1238
void reset_pmap_to_local()
Definition worlddc.h:695
itemfun(const keyT &key, memfunT memfun)
Definition worlddc.h:1074
const pairT const_pairT
Definition worlddc.h:570
std::vector< keyT > * move_list
Tempoary used to record data that needs redistributing.
Definition worlddc.h:604
internal_containerT::iterator internal_iteratorT
Definition worlddc.h:577
WorldContainerImpl< keyT, valueT, hashfunT > implT
Definition worlddc.h:571
std::size_t size() const
Definition worlddc.h:917
void redistribute_phase1(const std::shared_ptr< WorldDCPmapInterface< keyT > > &newpmap)
Definition worlddc.h:1161
internal_containerT::const_iterator internal_const_iteratorT
Definition worlddc.h:578
std::shared_ptr< WorldDCPmapInterface< keyT > > pmap
Function/class to map from keys to owning process.
Definition worlddc.h:600
virtual ~WorldContainerImpl()
Definition worlddc.h:680
void do_replicate(World &world)
Definition worlddc.h:856
std::shared_ptr< WorldDCPmapInterface< keyT > > & get_pmap()
Definition worlddc.h:690
internal_containerT local
Locally owned data.
Definition worlddc.h:603
ConcurrentHashMap< keyT, valueT, hashfunT > internal_containerT
Definition worlddc.h:573
void find_const_success_handler(const RemoteReference< FutureImpl< const_iterator > > &ref, const pairT &datum)
Handles successful const find response.
Definition worlddc.h:658
void insert_batch(const std::vector< pairT > &boxes)
Definition worlddc.h:956
const_iterator begin() const
Definition worlddc.h:1012
void erase(InIter it)
Definition worlddc.h:988
void replicate(bool fence)
Definition worlddc.h:714
const_iterator end() const
Definition worlddc.h:1022
bool is_local(const keyT &key) const
Definition worlddc.h:898
void redistribute_phase3()
Definition worlddc.h:1207
bool rank_replication_complete_
True if the last replicate() completed and no reset followed.
Definition worlddc.h:601
void find_failure_handler(const RemoteReference< FutureImpl< iterator > > &ref)
Handles unsuccessful find response.
Definition worlddc.h:634
ProcessID owner(const keyT &key) const
Definition worlddc.h:903
void erase(InIter first, InIter last)
Definition worlddc.h:996
void find_const_handler(ProcessID requestor, const keyT &key, const RemoteReference< FutureImpl< const_iterator > > &ref)
Handles const find request.
Definition worlddc.h:644
void replicate_on_hosts(bool fence)
Definition worlddc.h:740
const std::shared_ptr< WorldDCPmapInterface< keyT > > & get_pmap() const
Definition worlddc.h:685
iterator begin()
Definition worlddc.h:1007
Future< const_iterator > find(const keyT &key) const
Definition worlddc.h:1027
const ProcessID me
My MPI rank.
Definition worlddc.h:602
iterator end()
Definition worlddc.h:1017
std::map< ProcessID, std::vector< keyT > > coalesced_move_
Temporary: keys to move, bucketed by destination (coalesced redistribute).
Definition worlddc.h:605
WorldContainerIterator< internal_const_iteratorT > const_iterator
Definition worlddc.h:584
internal_containerT::const_accessor const_accessor
Definition worlddc.h:580
Iterator for distributed container wraps the local iterator.
Definition worlddc.h:417
WorldContainerIterator(const WorldContainerIterator &other)
Definition worlddc.h:446
WorldContainerIterator(const internal_iteratorT &it)
Initializes from a local iterator.
Definition worlddc.h:436
WorldContainerIterator & operator++()
Pre-increment of an iterator (i.e., ++it) — local iterators only.
Definition worlddc.h:487
std::iterator_traits< internal_iteratorT >::iterator_category iterator_category
Definition worlddc.h:419
void copy(const WorldContainerIterator< iteratorT > &other)
Definition worlddc.h:537
std::iterator_traits< internal_iteratorT >::pointer pointer
Definition worlddc.h:422
bool operator==(const WorldContainerIterator &other) const
Determines if two iterators are identical.
Definition worlddc.h:472
const internal_iteratorT & get_internal_iterator() const
Private: (or should be) Returns iterator of internal container.
Definition worlddc.h:515
friend class WorldContainerIterator
Definition worlddc.h:534
WorldContainerIterator & operator=(const WorldContainerIterator &other)
Assignment.
Definition worlddc.h:465
bool is_cached() const
Returns true if this is non-local or cached value.
Definition worlddc.h:521
WorldContainerIterator operator++(int)
Definition worlddc.h:494
WorldContainerIterator(const value_type &v)
Initializes to cache a remote value.
Definition worlddc.h:440
pointer operator->() const
Iterators dereference to std::pair<const keyT,valueT>.
Definition worlddc.h:503
std::iterator_traits< internal_iteratorT >::reference reference
Definition worlddc.h:423
void serialize(const Archive &)
Definition worlddc.h:527
std::iterator_traits< internal_iteratorT >::value_type value_type
Definition worlddc.h:420
WorldContainerIterator(const WorldContainerIterator< iteratorT > &other)
Definition worlddc.h:453
WorldContainerIterator()
Default constructor makes a local uninitialized value.
Definition worlddc.h:432
internal_const_iteratorT it
Definition worlddc.h:426
reference operator*() const
Iterators dereference to std::pair<const keyT,valueT>.
Definition worlddc.h:509
std::iterator_traits< internal_iteratorT >::difference_type difference_type
Definition worlddc.h:421
bool operator!=(const WorldContainerIterator &other) const
Determines if two iterators are different.
Definition worlddc.h:479
~WorldContainerIterator()
Definition worlddc.h:459
Makes a distributed container with specified attributes.
Definition worlddc.h:1302
void process_pending()
Process pending messages.
Definition worlddc.h:1648
WorldContainer(World &world, bool do_pending=true, const hashfunT &hf=hashfunT())
Makes an initialized, empty container with default data distribution (no communication).
Definition worlddc.h:1342
const hashfunT & get_hash() const
Returns a reference to the hashing functor.
Definition worlddc.h:1637
bool find(accessor &acc, const keyT &key)
Write access to LOCAL value by key. Returns true if found, false otherwise (always false for remote).
Definition worlddc.h:1469
bool probe(const keyT &key) const
Returns true if local data is immediately available (no communication).
Definition worlddc.h:1506
void redistribute_coalesced_phase2(std::size_t cap_boxes, bool rotate=true)
Definition worlddc.h:1449
const_iterator begin() const
Returns an iterator to the beginning of the local data (no communication).
Definition worlddc.h:1559
void replace(const keyT &key, const valueT &value)
Inserts/replaces key+value pair (non-blocking communication if key not local).
Definition worlddc.h:1463
bool insert(const_accessor &acc, const keyT &key)
Read access to LOCAL value by key. Returns true if inserted, false if already exists (throws if remot...
Definition worlddc.h:1490
iterator begin()
Returns an iterator to the beginning of the local data (no communication).
Definition worlddc.h:1552
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const TaskAttributes &attr=TaskAttributes()) const
Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T) const" in process owning item (non-blocking ...
Definition worlddc.h:2139
WorldContainer(World &world, const std::shared_ptr< WorldDCPmapInterface< keyT > > &pmap, bool do_pending=true, const hashfunT &hf=hashfunT())
Makes an initialized, empty container (no communication).
Definition worlddc.h:1358
Future< iterator > find(const keyT &key)
Returns a future iterator (non-blocking communication if key not local).
Definition worlddc.h:1534
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6) const
Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T) const" to item (non-blocking comm ...
Definition worlddc.h:1879
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const arg7T &arg7) const
Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T,arg7T) const" to item (non-blocking...
Definition worlddc.h:1890
Future< const_iterator > const_futureT
Definition worlddc.h:1314
bool is_replicated() const
Definition worlddc.h:1402
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> task(const keyT &key, memfunT memfun, const arg1T &arg1, const TaskAttributes &attr=TaskAttributes())
Adds task "resultT memfun(arg1T)" in process owning item (non-blocking comm if remote).
Definition worlddc.h:1928
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5) const
Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T) const" to item (non-blocking comm if rem...
Definition worlddc.h:1869
ProcessID owner(const keyT &key) const
Returns processor that logically owns key (no communication).
Definition worlddc.h:1516
implT::const_iterator const_iterator
Definition worlddc.h:1310
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const TaskAttributes &attr=TaskAttributes()) const
Adds task "resultT memfun(arg1T,arg2T) const" in process owning item (non-blocking comm if remote).
Definition worlddc.h:2109
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> task(const keyT &key, memfunT memfun, const TaskAttributes &attr=TaskAttributes()) const
Adds task "resultT memfun() const" in process owning item (non-blocking comm if remote).
Definition worlddc.h:2089
WorldContainer()
Makes an uninitialized container (no communication).
Definition worlddc.h:1330
void serialize(const archive::BufferOutputArchive &ar)
(de)Serialize — !! ONLY for purpose of interprocess communication
Definition worlddc.h:2205
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3)
Sends message "resultT memfun(arg1T,arg2T,arg3T)" to item (non-blocking comm if remote).
Definition worlddc.h:1729
void replicate(bool fence=true)
Definition worlddc.h:1427
virtual ~WorldContainer()
Destructor passes ownership of implementation to world for deferred cleanup.
Definition worlddc.h:2235
void erase(const keyT &key)
Erases entry from container (non-blocking comm if remote).
Definition worlddc.h:1587
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5)
Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T)" to item (non-blocking comm if remote).
Definition worlddc.h:1767
void reset_pmap_to_local()
Returns shared pointer to the process mapping.
Definition worlddc.h:1631
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> send(const keyT &key, const memfunT &memfun, const arg1T &arg1)
Sends message "resultT memfun(arg1T)" to item (non-blocking comm if remote).
Definition worlddc.h:1684
const uniqueidT & id() const
Returns the associated unique id ... must be initialized.
Definition worlddc.h:2228
void redistribute_coalesced_phase1(const std::shared_ptr< WorldDCPmapInterface< keyT > > &newpmap)
Definition worlddc.h:1440
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const arg7T &arg7, const TaskAttributes &attr=TaskAttributes())
Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T,arg7T)" in process owning item (non-blo...
Definition worlddc.h:2069
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const TaskAttributes &attr=TaskAttributes())
Adds task "resultT memfun(arg1T,arg2T)" in process owning item (non-blocking comm if remote).
Definition worlddc.h:1949
WorldContainerImpl< Key< NDIM >, FunctionNode< T, NDIM >, Hash< Key< NDIM > > > implT
Definition worlddc.h:1307
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2) const
Sends message "resultT memfun(arg1T,arg2T) const" to item (non-blocking comm if remote).
Definition worlddc.h:1839
void replace(const pairT &datum)
Inserts/replaces key+value pair (non-blocking communication if key not local).
Definition worlddc.h:1456
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const TaskAttributes &attr=TaskAttributes()) const
Adds task "resultT memfun(arg1T,arg2T,arg3T) const" in process owning item (non-blocking comm if remo...
Definition worlddc.h:2119
const std::shared_ptr< WorldDCPmapInterface< keyT > > & get_pmap() const
Returns shared pointer to the process mapping.
Definition worlddc.h:1624
std::shared_ptr< WorldDCPmapInterface< keyT > > & get_impl()
Definition worlddc.h:1417
void replace(input_iterator &start, input_iterator &end)
Inserts pairs (non-blocking communication if key(s) not local).
Definition worlddc.h:1498
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> task(const keyT &key, memfunT memfun, const arg1T &arg1, const TaskAttributes &attr=TaskAttributes()) const
Adds task "resultT memfun(arg1T) const" in process owning item (non-blocking comm if remote).
Definition worlddc.h:2099
bool insert(accessor &acc, const keyT &key)
Write access to LOCAL value by key. Returns true if inserted, false if already exists (throws if remo...
Definition worlddc.h:1483
Future< iterator > futureT
Definition worlddc.h:1313
void erase(const iterator &it)
Erases entry corresponding to local iterator (no communication).
Definition worlddc.h:1594
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const TaskAttributes &attr=TaskAttributes()) const
Adds task "resultT memfun(arg1T,arg2T,arg3T, arg4T) const" in process owning item (non-blocking comm ...
Definition worlddc.h:2129
void erase(const iterator &start, const iterator &finish)
Erases range defined by local iterators (no communication).
Definition worlddc.h:1601
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4) const
Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T) const" to item (non-blocking comm if remote).
Definition worlddc.h:1859
bool is_distributed() const
Definition worlddc.h:1398
WorldContainer(const WorldContainer &other)
Copy constructor is shallow (no communication).
Definition worlddc.h:1372
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const TaskAttributes &attr=TaskAttributes())
Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T)" in process owning item (non-blocking ...
Definition worlddc.h:2043
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const arg7T &arg7)
Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T,arg7T)" to item (non-blocking comm ...
Definition worlddc.h:1805
World & get_world() const
Returns the world associated with this container.
Definition worlddc.h:1411
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> send(const keyT &key, memfunT memfun) const
Sends message "resultT memfun() const" to item (non-blocking comm if remote).
Definition worlddc.h:1819
friend void swap(WorldContainer &, WorldContainer &)
implT::iterator iterator
Definition worlddc.h:1309
DistributionType get_distribution_type() const
return the way data is distributed
Definition worlddc.h:1393
std::size_t size() const
Returns the number of local entries (no communication).
Definition worlddc.h:1617
containerT & operator=(const containerT &other)
Assignment is shallow (no communication).
Definition worlddc.h:1382
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const TaskAttributes &attr=TaskAttributes())
Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T)" in process owning item (non-blocking comm i...
Definition worlddc.h:2018
bool find(const_accessor &acc, const keyT &key) const
Read access to LOCAL value by key. Returns true if found, false otherwise (always false for remote).
Definition worlddc.h:1476
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const TaskAttributes &attr=TaskAttributes())
Adds task "resultT memfun(arg1T,arg2T,arg3T)" in process owning item (non-blocking comm if remote).
Definition worlddc.h:1971
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4)
Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T)" to item (non-blocking comm if remote).
Definition worlddc.h:1748
void serialize(const archive::BufferInputArchive &ar)
(de)Serialize — !! ONLY for purpose of interprocess communication
Definition worlddc.h:2214
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> task(const keyT &key, memfunT memfun, const TaskAttributes &attr=TaskAttributes())
Adds task "resultT memfun()" in process owning item (non-blocking comm if remote).
Definition worlddc.h:1908
bool is_local(const keyT &key) const
Returns true if the key maps to the local processor (no communication).
Definition worlddc.h:1523
const_iterator end() const
Returns an iterator past the end of the local data (no communication).
Definition worlddc.h:1573
void serialize(const Archive &ar)
(de)Serialize — Local data only to/from anything except Buffer*Archive and Parallel*Archive
Definition worlddc.h:2168
bool is_host_replicated() const
Definition worlddc.h:1406
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const TaskAttributes &attr=TaskAttributes()) const
Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T) const" in process owning item (non-blo...
Definition worlddc.h:2149
void clear()
Clears all local data (no communication).
Definition worlddc.h:1610
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const TaskAttributes &attr=TaskAttributes())
Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T)" in process owning item (non-blocking comm if remo...
Definition worlddc.h:1994
Future< MEMFUN_RETURNT(memfunT)> send(const keyT &key, memfunT memfun)
Sends message "resultT memfun()" to item (non-blocking comm if remote).
Definition worlddc.h:1665
implT::const_accessor const_accessor
Definition worlddc.h:1312
std::shared_ptr< implT > p
Definition worlddc.h:1317
Future< const_iterator > find(const keyT &key) const
Returns a future iterator (non-blocking communication if key not local).
Definition worlddc.h:1545
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3) const
Sends message "resultT memfun(arg1T,arg2T,arg3T) const" to item (non-blocking comm if remote).
Definition worlddc.h:1849
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6)
Sends message "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T)" to item (non-blocking comm if rem...
Definition worlddc.h:1786
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> send(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2)
Sends message "resultT memfun(arg1T,arg2T)" to item (non-blocking comm if remote).
Definition worlddc.h:1707
void replicate_on_hosts(bool fence=true)
replicates this WorldContainer on all hosts (one PID per host)
Definition worlddc.h:1433
void check_initialized() const
Definition worlddc.h:1319
WorldContainer< Key< NDIM >, FunctionNode< T, NDIM >, Hash< Key< NDIM > > > containerT
Definition worlddc.h:1306
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> task(const keyT &key, memfunT memfun, const arg1T &arg1, const arg2T &arg2, const arg3T &arg3, const arg4T &arg4, const arg5T &arg5, const arg6T &arg6, const arg7T &arg7, const TaskAttributes &attr=TaskAttributes()) const
Adds task "resultT memfun(arg1T,arg2T,arg3T,arg4T,arg5T,arg6T,arg7T) const" in process owning item (n...
Definition worlddc.h:2159
Future< REMFUTURE(MEMFUN_RETURNT(memfunT))> send(const keyT &key, memfunT memfun, const arg1T &arg1) const
Sends message "resultT memfun(arg1T) const" to item (non-blocking comm if remote).
Definition worlddc.h:1829
implT::accessor accessor
Definition worlddc.h:1311
Default process map is "random" using madness::hash(key).
Definition worlddc.h:264
ProcessID owner(const keyT &key) const
Maps key to processor.
Definition worlddc.h:275
WorldDCDefaultPmap(World &world, const hashfunT &hf=hashfunT())
Definition worlddc.h:270
const int nproc
Definition worlddc.h:266
hashfunT hashfun
Definition worlddc.h:267
Local process map will always return the current process as owner.
Definition worlddc.h:288
ProcessID owner(const keyT &key) const override
Maps key to processor.
Definition worlddc.h:294
WorldDCLocalPmap(World &world)
Definition worlddc.h:293
ProcessID me
Definition worlddc.h:290
DistributionType distribution_type() const override
by default the map is distributed
Definition worlddc.h:299
Definition worlddc.h:326
DistributionType distribution_type() const override
by default the map is distributed
Definition worlddc.h:342
WorldDCNodeReplicatedPmap(World &world, const std::map< std::string, std::vector< long > > ranks_per_host)
Definition worlddc.h:333
ProcessID myowner
Definition worlddc.h:327
ProcessID owner(const keyT &key) const override
owner is the lowest rank on the node, same for all keys
Definition worlddc.h:338
Interface to be provided by any process map.
Definition worlddc.h:128
void redistribute(World &world, const std::shared_ptr< WorldDCPmapInterface< keyT > > &newpmap)
Invoking this switches all registered objects from this process map to the new one.
Definition worlddc.h:183
virtual DistributionType distribution_type() const
by default the map is distributed
Definition worlddc.h:148
virtual ProcessID single_owner() const
Definition worlddc.h:156
void print_data_sizes(World &world, const std::string msg="") const
Prints size info to std::cout.
Definition worlddc.h:239
std::size_t global_size(World &world) const
Counts global number of entries in all containers associated with this process map.
Definition worlddc.h:216
virtual ProcessID owner(const keyT &key) const =0
Maps key to processor.
void deregister_callback(ptrT ptr)
Deregisters object for receipt of redistribute callbacks.
Definition worlddc.h:172
void register_callback(ptrT ptr)
Registers object for receipt of redistribute callbacks.
Definition worlddc.h:164
virtual void print() const
Definition worlddc.h:145
std::size_t local_size() const
Counts local number of entries in all containers associated with this process map.
Definition worlddc.h:226
std::set< ptrT > ptrs
Definition worlddc.h:134
virtual ~WorldDCPmapInterface()
Definition worlddc.h:143
WorldDCRedistributeInterface< keyT > * ptrT
Definition worlddc.h:130
virtual std::size_t size() const =0
virtual void redistribute_phase1(const std::shared_ptr< WorldDCPmapInterface< keyT > > &newmap)=0
virtual ~WorldDCRedistributeInterface()
Definition worlddc.h:83
WorldDCSingleOwnerPmap(ProcessID owner)
Definition worlddc.h:317
const ProcessID owner_
Definition worlddc.h:314
ProcessID owner(const keyT &) const override
Maps key to processor.
Definition worlddc.h:318
ProcessID single_owner() const override
Definition worlddc.h:319
void broadcast_serializable(objT &obj, ProcessID root)
Broadcast a serializable object.
Definition worldgop.h:774
void fence(bool debug=false)
Synchronizes all processes in communicator AND globally ensures no pending AM or tasks.
Definition worldgop.cc:177
void broadcast(void *buf, size_t nbyte, ProcessID root, bool dowork=true, Tag bcast_tag=-1)
Broadcasts bytes from process root while still processing AM & tasks.
Definition worldgop.cc:189
std::vector< T > concat0(const std::vector< T > &v, size_t bufsz=1024 *1024)
Concatenate an STL vector of serializable stuff onto node 0.
Definition worldgop.h:973
void sum(T *buf, size_t nelem)
Inplace global sum while still processing AM & tasks.
Definition worldgop.h:890
void Send(const T *buf, long lenbuf, int dest, int tag=SafeMPI::DEFAULT_SEND_RECV_TAG) const
Send array of lenbuf elements to process dest.
Definition worldmpi.h:347
void Recv(T *buf, long lenbuf, int src, int tag) const
Receive data of up to lenbuf elements from process src.
Definition worldmpi.h:374
Implements most parts of a globally addressable object (via unique ID).
Definition world_object.h:491
WorldObject(const WorldObject &other)
Definition world_object.h:500
detail::task_result_type< memfnT >::futureT send(ProcessID dest, memfnT memfn) const
Definition world_object.h:858
detail::task_result_type< memfnT >::futureT task(ProcessID dest, memfnT memfn, const TaskAttributes &attr=TaskAttributes()) const
Definition world_object.h:1132
Future< bool > for_each(const rangeT &range, const opT &op)
Apply op(item) on all items in range.
Definition world_task_queue.h:572
void add(TaskInterface *t)
Add a new local task, taking ownership of the pointer.
Definition world_task_queue.h:466
void fence()
Returns after all local tasks have completed.
Definition world_task_queue.h:1384
A parallel world class.
Definition world.h:134
WorldTaskQueue & taskq
Task queue.
Definition world.h:215
ProcessID rank() const
Returns the process rank in this World (same as MPI_Comm_rank()).
Definition world.h:344
WorldMpiInterface & mpi
MPI interface.
Definition world.h:213
ProcessID size() const
Returns the number of processes in this World (same as MPI_Comm_size()).
Definition world.h:354
WorldGopInterface & gop
Global operations.
Definition world.h:216
bool dofence() const
Check if we should fence around a read/write operation.
Definition parallel_archive.h:295
World * get_world() const
Returns a pointer to the world.
Definition parallel_archive.h:130
bool is_io_node() const
Returns true if this node is doing physical I/O.
Definition parallel_archive.h:122
int num_io_clients() const
Returns the number of I/O clients for this node, including self (zero if not an I/O node).
Definition parallel_archive.h:114
ProcessID io_node(ProcessID rank) const
Returns the process doing I/O for given node.
Definition parallel_archive.h:99
ProcessID my_io_node() const
Returns the process doing I/O for this node.
Definition parallel_archive.h:106
Archive & local_archive() const
Returns a reference to the local archive.
Definition parallel_archive.h:248
Wraps an archive around a memory buffer for input.
Definition buffer_archive.h:134
Wraps an archive around a memory buffer for output.
Definition buffer_archive.h:59
std::size_t size() const
Return the amount of data stored (counted) in the buffer.
Definition buffer_archive.h:123
Archive allowing buffering, deserialization of data, and point-to-point communication between process...
Definition mpi_archive.h:180
Archive allowing buffering, serialization of data, and point-to-point communication between processes...
Definition mpi_archive.h:118
void flush() const
Send all data in the buffer to the destination process.
Definition mpi_archive.h:158
An archive for storing local or parallel data, wrapping a BinaryFstreamInputArchive.
Definition parallel_archive.h:366
An archive for storing local or parallel data wrapping a BinaryFstreamOutputArchive.
Definition parallel_archive.h:321
Objects that implement their own parallel archive interface should derive from this class.
Definition parallel_archive.h:58
Wraps an archive around an STL vector for output.
Definition vector_archive.h:55
Class for unique global IDs.
Definition uniqueid.h:53
char * p(char *buf, const char *name, int k, int initial_level, double thresh, int order)
Definition derivatives.cc:72
void run(World &world, ansatzT ansatz, const int nuclear_charge, const commandlineparser &parser, const int nstates)
Definition dirac-hatom.cc:1392
static void load(const ParallelInputArchive< localarchiveT > &ar, WorldContainer< keyT, valueT > &t)
Read container from parallel archive.
Definition worlddc.h:2561
static const double v
Definition hatom_sf_dirac.cc:20
#define MADNESS_CHECK(condition)
Check a condition — even in a release build the condition is always evaluated so it can have side eff...
Definition madness_exception.h:182
#define MADNESS_EXCEPTION(msg, value)
Macro for throwing a MADNESS exception.
Definition madness_exception.h:119
#define MADNESS_ASSERT(condition)
Assert a condition that should be free of side-effects since in release builds this might be a no-op.
Definition madness_exception.h:134
#define MADNESS_CHECK_THROW(condition, msg)
Check a condition — even in a release build the condition is always evaluated so it can have side eff...
Definition madness_exception.h:207
Implements archives to serialize data for MPI.
const unsigned char archive_typeinfo< T >::cookie
Definition archive_type_names.cc:44
void deferred_cleanup(World &world, const std::shared_ptr< objT > &p, bool assume_p_is_unique=false)
Defer the cleanup of a shared pointer to the end of the next fence.
Definition deferred_cleanup.h:135
Namespace for all elements and tools of MADNESS.
Definition DFConvergence.h:9
DistributionType from_string(std::string type)
Definition worlddc.h:109
std::ostream & operator<<(std::ostream &os, const particle< PDIM > &p)
Definition lowrankfunction.h:452
std::string to_string(const Representation r)
Definition Restart.h:64
DistributionType
some introspection of how data is distributed
Definition worlddc.h:87
@ NodeReplicated
even if there are several ranks per node
Definition worlddc.h:90
@ Distributed
no replication of the container, the container is distributed over the world
Definition worlddc.h:88
@ RankReplicated
replicate the container over all world ranks
Definition worlddc.h:89
std::shared_ptr< WorldDCPmapInterface< Key< NDIM > > > FunctionDefaults< NDIM >::pmap
Definition mraimpl.h:3898
std::vector< int > primary_ranks_per_host(World &world, const std::map< std::string, std::vector< long > > &ranks_per_host1)
Definition ranks_and_hosts.cpp:94
Function< T, NDIM > sum(World &world, const std::vector< Function< T, NDIM > > &f, bool fence=true)
Returns new function — q = sum_i f[i].
Definition vmra.h:1774
DistributionType validate_distribution_type(const dcT &dc)
check distribution type of WorldContainer – global communication
Definition worlddc.h:350
NDIM & f
Definition mra.h:2817
double wall_time()
Returns the wall time in seconds relative to an arbitrary origin.
Definition timers.cc:48
void print(const T &t, Ts &&... ts)
Print items to std::cout (items separated by spaces) and terminate with a new line.
Definition print.h:232
const Future< void > Future< void >::value
Definition future.cc:44
long lowest_rank_on_host_of_rank(const std::map< std::string, std::vector< long > > ranks_per_host1, int rank)
Definition ranks_and_hosts.cpp:81
std::map< std::string, std::vector< long > > ranks_per_host(World &universe)
for each host, return a list of its ranks
Definition ranks_and_hosts.cpp:60
void swap(Function< R, MDIM > &f1, Function< R, MDIM > &f2)
Definition mra.h:3149
Definition mraimpl.h:53
void advance(madness::Hash_private::HashIterator< hashT > &it, const distT &dist)
Definition worldhashmap.h:610
static const double d
Definition nonlinschro.cc:121
Implements ParallelInputArchive and ParallelOutputArchive for parallel serialization of data.
static const double c
Definition relops.cc:10
Definition worlddc.h:1174
bool operator()(typename rangeT::iterator &iterator) const
Definition worlddc.h:1179
implT * impl
Definition worlddc.h:1175
P2Op(const P2Op &p)
Definition worlddc.h:1178
P2Op(implT *impl)
Definition worlddc.h:1177
Range< typename std::vector< keyT >::const_iterator > rangeT
Definition worlddc.h:1176
World & world
Memoized reference to the world to which this object belongs.
Definition world_object.h:348
World & get_world() const
Definition world_object.h:446
Default load of an object via serialize(ar, t).
Definition archive.h:667
static void postamble_store(const Archive &)
By default there is no postamble.
Definition archive.h:546
static void preamble_store(const Archive &ar)
Serialize a cookie for type checking.
Definition archive.h:536
static void store(const ParallelOutputArchive< VectorOutputArchive > &ar, const WorldContainer< keyT, valueT > &t)
Definition worlddc.h:2264
static void store(const ParallelOutputArchive< localarchiveT > &ar, const WorldContainer< keyT, valueT > &t)
Definition worlddc.h:2492
Default store of an object via serialize(ar, t).
Definition archive.h:612
std::pair< int, double > valueT
Definition test_binsorter.cc:6
int me
Definition test_binsorter.cc:10
const double offset
Definition testfuns.cc:143
double source(const coordT &r)
Definition testperiodic.cc:48
#define REMFUTURE(T)
Macro to determine type of future (by removing wrapping Future template).
Definition type_traits.h:163
#define MEMFUN_RETURNT(MEMFUN)
Macro to make member function type traits easier to use.
Definition type_traits.h:773
Defines and implements WorldObject.
Defines and implements a concurrent hashmap.
int ProcessID
Used to clearly identify process number/rank.
Definition worldtypes.h:43
int Tag
Used to clearly identify message tag/type.
Definition worldtypes.h:44
Key< D > keyT
Definition writecoeff2.cc:11