12 #include "collection.hpp"
16 #include "serialization.hpp"
17 #include "detail/collectives.hpp"
22 #include "detail/block_traits.hpp"
49 typedef std::vector<BaseCommand*> Commands;
52 using Skip = std::function<bool(int, const Master&)>;
55 struct NeverSkip {
bool operator()(
int i,
const Master& master)
const {
return false; } };
58 typedef Collection::Create CreateBlock;
59 typedef Collection::Destroy DestroyBlock;
60 typedef Collection::Save SaveBlock;
61 typedef Collection::Load LoadBlock;
70 using Callback = std::function<void(Block*, const ProxyWithLink&)>;
74 virtual bool unload_incoming(
const Master& master,
int from,
int to,
size_t size)
const =0;
75 virtual bool unload_outgoing(
const Master& master,
int from,
size_t size)
const =0;
83 bool unload_incoming(
const Master& master,
int from,
int to,
size_t sz)
const {
return sz > size; }
84 bool unload_outgoing(
const Master& master,
int from,
size_t sz)
const {
return sz > size*master.outgoing_count(from); }
97 std::shared_ptr<MemoryBuffer> message;
111 struct tags {
enum { queue, piece }; };
113 typedef std::list<InFlightSend> InFlightSendsList;
114 typedef std::map<int, InFlightRecv> InFlightRecvsMap;
115 typedef std::list<int> ToSendList;
116 typedef std::list<Collective> CollectivesList;
117 typedef std::map<int, CollectivesList> CollectivesMap;
122 QueueRecord(
size_t s = 0,
int e = -1): size(s), external(e) {}
127 typedef std::map<int, QueueRecord> InQueueRecords;
128 typedef std::map<int, MemoryBuffer> IncomingQueues;
129 typedef std::map<BlockID, MemoryBuffer> OutgoingQueues;
130 typedef std::map<BlockID, QueueRecord> OutQueueRecords;
133 InQueueRecords records;
134 IncomingQueues queues;
140 OutQueueRecords external_local;
141 OutgoingQueues queues;
143 typedef std::map<int, IncomingQueuesRecords> IncomingQueuesMap;
144 typedef std::map<int, OutgoingQueuesRecord> OutgoingQueuesMap;
148 IncomingQueuesMap map;
151 typedef std::map<int, IncomingRound> IncomingRoundMap;
167 CreateBlock create = 0,
168 DestroyBlock destroy = 0,
173 blocks_(create, destroy, storage,
save, load),
174 queue_policy_(q_policy),
176 threads_(threads == -1 ?
thread::hardware_concurrency() : threads),
184 ~
Master() { set_immediate(
true); clear();
delete queue_policy_; }
186 inline void destroy(
int i) {
if (blocks_.own()) blocks_.destroy(i); }
188 inline int add(
int gid,
void* b, Link* l);
192 inline void* block(
int i)
const {
return blocks_.find(i); }
193 template<
class Block>
194 Block* block(
int i)
const {
return static_cast<Block*
>(block(i)); }
195 inline Link* link(
int i)
const {
return links_[i]; }
196 inline int loaded_block()
const {
return blocks_.available(); }
198 inline void unload(
int i);
199 inline void load(
int i);
200 void unload(std::vector<int>& loaded) {
for(
unsigned i = 0; i < loaded.size(); ++i) unload(loaded[i]); loaded.clear(); }
201 void unload_all() {
for(
unsigned i = 0; i <
size(); ++i)
if (block(i) != 0) unload(i); }
202 inline bool has_incoming(
int i)
const;
204 inline void unload_queues(
int i);
205 inline void unload_incoming(
int gid);
206 inline void unload_outgoing(
int gid);
207 inline void load_queues(
int i);
208 inline void load_incoming(
int gid);
209 inline void load_outgoing(
int gid);
217 void*
get(
int i) {
return blocks_.get(i); }
219 int gid(
int i)
const {
return gids_[i]; }
221 int lid(
int gid)
const {
return local(gid) ? lids_.find(gid)->second : -1; }
223 bool local(
int gid)
const {
return lids_.find(gid) != lids_.end(); }
227 inline void process_collectives();
230 ProxyWithLink proxy(
int i)
const;
233 unsigned size()
const {
return blocks_.size(); }
234 void* create()
const {
return blocks_.create(); }
237 int limit()
const {
return limit_; }
238 int threads()
const {
return threads_; }
239 int in_memory()
const {
return *blocks_.in_memory().const_access(); }
241 void set_threads(
int threads) { threads_ = threads; }
243 CreateBlock creator()
const {
return blocks_.creator(); }
244 DestroyBlock destroyer()
const {
return blocks_.destroyer(); }
245 LoadBlock loader()
const {
return blocks_.loader(); }
246 SaveBlock saver()
const {
return blocks_.saver(); }
249 template<
class Block>
250 void foreach_(
const Callback<Block>& f,
const Skip& s = NeverSkip());
253 void foreach(
const F& f,
const Skip& s = NeverSkip())
255 using Block =
typename detail::block_traits<F>::type;
256 foreach_<Block>(f, s);
259 inline void execute();
261 bool immediate()
const {
return immediate_; }
262 void set_immediate(
bool i) {
if (i && !immediate_) execute(); immediate_ = i; }
266 IncomingQueues& incoming(
int gid) {
return incoming_[exchange_round_].map[
gid].queues; }
267 OutgoingQueues& outgoing(
int gid) {
return outgoing_[
gid].queues; }
268 CollectivesList& collectives(
int gid) {
return collectives_[
gid]; }
269 size_t incoming_count(
int gid)
const
271 IncomingRoundMap::const_iterator round_it = incoming_.find(exchange_round_);
272 if (round_it == incoming_.end())
274 IncomingQueuesMap::const_iterator queue_it = round_it->second.map.find(gid);
275 if (queue_it == round_it->second.map.end())
277 return queue_it->second.queues.size();
279 size_t outgoing_count(
int gid)
const { OutgoingQueuesMap::const_iterator it = outgoing_.find(gid);
if (it == outgoing_.end())
return 0;
return it->second.queues.size(); }
281 void set_expected(
int expected) { expected_ = expected; }
282 void add_expected(
int i) { expected_ += i; }
283 int expected()
const {
return expected_; }
284 void replace_link(
int i, Link* link) { expected_ -= links_[i]->size_unique();
delete links_[i]; links_[i] = link; expected_ += links_[i]->size_unique(); }
292 inline void comm_exchange(ToSendList& to_send,
int out_queues_limit);
295 void cancel_requests();
298 inline void show_incoming_records()
const;
301 std::vector<Link*> links_;
303 std::vector<int> gids_;
304 std::map<int, int> lids_;
306 QueuePolicy* queue_policy_;
310 ExternalStorage* storage_;
314 mpi::communicator comm_;
315 IncomingRoundMap incoming_;
316 OutgoingQueuesMap outgoing_;
317 InFlightSendsList inflight_sends_;
318 InFlightRecvsMap inflight_recvs_;
319 CollectivesMap collectives_;
326 fast_mutex add_mutex_;
329 std::shared_ptr<spd::logger> log = get_logger();
330 stats::Profiler prof;
336 virtual void execute(
void* b,
const ProxyWithLink& cp)
const =0;
337 virtual bool skip(
int i,
const Master& master)
const =0;
340 template<
class Block>
343 Command(Callback<Block> f_,
const Skip& s_):
346 void execute(
void* b,
const ProxyWithLink& cp)
const override { f(static_cast<Block*>(b), cp); }
347 bool skip(
int i,
const Master& m)
const override {
return s(i,m); }
354 {
bool operator()(
int i,
const Master& master)
const {
return !master.has_incoming(i); } };
364 cop_(0) { swap(const_cast<Collective&>(other)); }
367 void init() { cop_->init(); }
368 void swap(
Collective& other) { std::swap(cop_, other.cop_); }
369 void update(
const Collective& other) { cop_->update(*other.cop_); }
371 void copy_from(
Collective& other)
const { cop_->copy_from(*other.cop_); }
372 void result_out(
void* x)
const { cop_->result_out(x); }
374 detail::CollectiveOp* cop_;
387 const std::deque<int>& blocks_,
392 local_limit(local_limit_),
398 master.log->debug(
"Processing with thread: {}", this_thread::get_id());
400 std::vector<int>
local;
403 int cur = (*idx.access())++;
405 if ((
size_t)cur >= blocks.size())
411 if (local.size() == (size_t)local_limit)
412 master.unload(local);
416 master.log->debug(
"Processing block: {}", master.
gid(i));
418 bool skip_block =
true;
419 for (
size_t cmd = 0; cmd < master.commands_.size(); ++cmd)
421 if (!master.commands_[cmd]->skip(i, master))
428 IncomingQueuesMap ¤t_incoming = master.incoming_[master.exchange_round_].map;
431 if (master.block(i) == 0)
432 master.load_queues(i);
434 for (
size_t cmd = 0; cmd < master.commands_.size(); ++cmd)
436 master.commands_[cmd]->execute(0, master.proxy(i));
439 current_incoming[master.
gid(i)].queues.clear();
440 current_incoming[master.
gid(i)].records.clear();
443 if (master.block(i) == 0)
444 master.unload_queues(i);
448 if (master.block(i) == 0)
450 if (local.size() == (size_t)local_limit)
451 master.unload(local);
457 for (
size_t cmd = 0; cmd < master.commands_.size(); ++cmd)
459 master.commands_[cmd]->execute(master.block(i), master.proxy(i));
462 current_incoming[master.
gid(i)].queues.clear();
463 current_incoming[master.
gid(i)].records.clear();
472 static void run(
void* bf) {
static_cast<ProcessBlock*
>(bf)->process(); }
475 const std::deque<int>& blocks;
485 for (
unsigned i = 0; i <
size(); ++i)
498 log->debug(
"Unloading block: {}", gid(i));
508 unload_incoming(gid(i));
509 unload_outgoing(gid(i));
514 unload_incoming(
int gid)
516 for (IncomingRoundMap::iterator round_itr = incoming_.begin(); round_itr != incoming_.end(); ++round_itr)
518 IncomingQueuesMap::iterator qmap_itr = round_itr->second.map.find(gid);
519 if (qmap_itr == round_itr->second.map.end())
523 IncomingQueuesRecords& in_qrs = qmap_itr->second;
524 for (InQueueRecords::iterator it = in_qrs.records.begin(); it != in_qrs.records.end(); ++it)
526 QueueRecord& qr = it->second;
527 if (queue_policy_->unload_incoming(*
this, it->first, gid, qr.size))
529 log->debug(
"Unloading queue: {} <- {}", gid, it->first);
530 qr.external = storage_->put(in_qrs.queues[it->first]);
538 unload_outgoing(
int gid)
540 OutgoingQueuesRecord& out_qr = outgoing_[gid];
542 size_t out_queues_size =
sizeof(size_t);
544 for (OutgoingQueues::iterator it = out_qr.queues.begin(); it != out_qr.queues.end(); ++it)
546 if (it->first.proc == comm_.rank())
continue;
548 out_queues_size +=
sizeof(BlockID);
549 out_queues_size +=
sizeof(size_t);
550 out_queues_size +=
sizeof(size_t);
551 out_queues_size += it->second.size();
554 if (queue_policy_->unload_outgoing(*
this, gid, out_queues_size -
sizeof(
size_t)))
556 log->debug(
"Unloading outgoing queues: {} -> ...; size = {}\n", gid, out_queues_size);
557 MemoryBuffer bb; bb.reserve(out_queues_size);
560 for (OutgoingQueues::iterator it = out_qr.queues.begin(); it != out_qr.queues.end();)
562 if (it->first.proc == comm_.rank())
565 if (queue_policy_->unload_incoming(*
this, gid, it->first.gid, it->second.size()))
567 QueueRecord& qr = out_qr.external_local[it->first];
568 qr.size = it->second.size();
569 qr.external = storage_->put(it->second);
571 out_qr.queues.erase(it++);
579 out_qr.queues.erase(it++);
587 out_qr.external = storage_->put(bb);
595 log->debug(
"Loading block: {}", gid(i));
605 load_incoming(gid(i));
606 load_outgoing(gid(i));
611 load_incoming(
int gid)
613 IncomingQueuesRecords& in_qrs = incoming_[exchange_round_].map[gid];
614 for (InQueueRecords::iterator it = in_qrs.records.begin(); it != in_qrs.records.end(); ++it)
616 QueueRecord& qr = it->second;
617 if (qr.external != -1)
619 log->debug(
"Loading queue: {} <- {}", gid, it->first);
620 storage_->get(qr.external, in_qrs.queues[it->first]);
628 load_outgoing(
int gid)
632 OutgoingQueuesRecord& out_qr = outgoing_[gid];
633 if (out_qr.external != -1)
636 storage_->get(out_qr.external, bb);
637 out_qr.external = -1;
641 for (
size_t i = 0; i < count; ++i)
653 {
return ProxyWithLink(Proxy(const_cast<Master*>(
this), gid(i)), block(i), link(i)); }
660 if (*blocks_.in_memory().const_access() == limit_)
667 gids_.push_back(gid);
669 int lid = gids_.size() - 1;
671 add_expected(l->size_unique());
680 void* b = blocks_.release(i);
681 delete link(i); links_[i] = 0;
688 has_incoming(
int i)
const
690 const IncomingQueuesRecords& in_qrs =
const_cast<Master&
>(*this).incoming_[exchange_round_].map[gid(i)];
691 for (InQueueRecords::const_iterator it = in_qrs.records.begin(); it != in_qrs.records.end(); ++it)
693 const QueueRecord& qr = it->second;
700 template<
class Block>
703 foreach_(
const Callback<Block>& f,
const Skip& skip)
705 auto scoped = prof.scoped(
"foreach");
716 log->debug(
"Entered execute()");
717 auto scoped = prof.scoped(
"execute");
721 for (
unsigned i = 0; i < size(); ++i)
728 if (commands_.empty())
732 std::deque<int> blocks;
733 for (
unsigned i = 0; i < size(); ++i)
737 blocks.push_front(i);
741 int blocks_per_thread;
744 num_threads = threads_;
745 blocks_per_thread = size();
749 num_threads = std::min(threads_, limit_);
750 blocks_per_thread = limit_/num_threads;
754 critical_resource<int> idx(0);
756 typedef ProcessBlock BlockFunctor;
760 typedef std::pair<thread*, BlockFunctor*> ThreadFunctorPair;
761 typedef std::list<ThreadFunctorPair> ThreadFunctorList;
762 ThreadFunctorList threads;
763 for (
unsigned i = 0; i < (unsigned)num_threads; ++i)
765 BlockFunctor* bf =
new BlockFunctor(*
this, blocks, blocks_per_thread, idx);
766 threads.push_back(ThreadFunctorPair(
new thread(&BlockFunctor::run, bf), bf));
770 for(ThreadFunctorList::iterator it = threads.begin(); it != threads.end(); ++it)
772 thread* t = it->first;
773 BlockFunctor* bf = it->second;
780 BlockFunctor bf(*
this, blocks, blocks_per_thread, idx);
781 BlockFunctor::run(&bf);
785 incoming_[exchange_round_].map.clear();
787 if (limit() != -1 && in_memory() > limit())
788 throw std::runtime_error(fmt::format(
"Fatal: {} blocks in memory, with limit {}", in_memory(), limit()));
791 for (
size_t i = 0; i < commands_.size(); ++i)
800 auto scoped = prof.scoped(
"exchange");
803 log->debug(
"Starting exchange");
806 for (
int i = 0; i < (int)size(); ++i)
808 OutgoingQueues& outgoing_queues = outgoing_[gid(i)].queues;
809 OutQueueRecords& external_local = outgoing_[gid(i)].external_local;
810 if (outgoing_queues.size() < (size_t)link(i)->size())
811 for (
unsigned j = 0; j < (unsigned)link(i)->size(); ++j)
813 if (external_local.find(link(i)->target(j)) == external_local.end())
814 outgoing_queues[link(i)->target(j)];
819 log->debug(
"Finished exchange");
826 template <
typename T>
838 template<
typename T>
struct is_mpi_datatype< diy::detail::VectorWindow<T> > {
typedef true_type type; };
840 template <
typename T>
841 struct mpi_datatype< diy::detail::VectorWindow<T> >
843 typedef diy::detail::VectorWindow<T> VecWin;
844 static MPI_Datatype datatype() {
return get_mpi_datatype<T>(); }
845 static const void* address(
const VecWin& x) {
return x.begin; }
846 static void* address(VecWin& x) {
return x.begin; }
847 static int count(
const VecWin& x) {
return static_cast<int>(x.count); }
857 comm_exchange(ToSendList& to_send,
int out_queues_limit)
859 static const size_t MAX_MPI_MESSAGE_COUNT = INT_MAX;
861 IncomingRound ¤t_incoming = incoming_[exchange_round_];
863 while(inflight_sends_.size() < (size_t)out_queues_limit && !to_send.empty())
865 int from = to_send.front();
868 for (OutQueueRecords::iterator it = outgoing_[from].external_local.begin(); it != outgoing_[from].external_local.end(); ++it)
870 int to = it->first.gid;
872 log->debug(
"Processing local queue: {} <- {} of size {}", to, from, it->second.size);
874 QueueRecord& in_qr = current_incoming.map[to].records[from];
875 bool in_external = block(lid(to)) == 0;
882 in_qr.size = it->second.size;
886 storage_->get(it->second.external, bb);
888 current_incoming.map[to].queues[from].swap(bb);
890 ++current_incoming.received;
892 outgoing_[from].external_local.clear();
894 if (outgoing_[from].external != -1)
898 OutgoingQueues& outgoing = outgoing_[from].queues;
899 for (OutgoingQueues::iterator it = outgoing.begin(); it != outgoing.end(); ++it)
901 BlockID to_proc = it->first;
902 int to = to_proc.gid;
903 int proc = to_proc.proc;
905 log->debug(
"Processing queue: {} <- {} of size {}", to, from, outgoing_[from].queues[to_proc].size());
908 if (proc == comm_.rank())
910 log->debug(
"Moving queue in-place: {} <- {}", to, from);
912 QueueRecord& in_qr = current_incoming.map[to].records[from];
913 bool in_external = block(lid(to)) == 0;
916 log->debug(
"Unloading outgoing directly as incoming: {} <- {}", to, from);
917 MemoryBuffer& bb = it->second;
918 in_qr.size = bb.size();
919 if (queue_policy_->unload_incoming(*
this, from, to, in_qr.size))
920 in_qr.external = storage_->put(bb);
923 MemoryBuffer& in_bb = current_incoming.map[to].queues[from];
930 log->debug(
"Swapping in memory: {} <- {}", to, from);
931 MemoryBuffer& bb = current_incoming.map[to].queues[from];
934 in_qr.size = bb.size();
938 ++current_incoming.received;
942 std::shared_ptr<MemoryBuffer> buffer = std::make_shared<MemoryBuffer>();
943 buffer->swap(it->second);
945 MessageInfo info{from, to, exchange_round_};
946 if (buffer->size() <= (MAX_MPI_MESSAGE_COUNT -
sizeof(info)))
950 inflight_sends_.emplace_back();
951 inflight_sends_.back().info = info;
952 inflight_sends_.back().request = comm_.isend(proc, tags::queue, buffer->buffer);
953 inflight_sends_.back().message = buffer;
957 int npieces =
static_cast<int>((buffer->size() + MAX_MPI_MESSAGE_COUNT - 1)/MAX_MPI_MESSAGE_COUNT);
960 std::shared_ptr<MemoryBuffer> hb = std::make_shared<MemoryBuffer>();
964 inflight_sends_.emplace_back();
965 inflight_sends_.back().info = info;
966 inflight_sends_.back().request = comm_.isend(proc, tags::piece, hb->buffer);
967 inflight_sends_.back().message = hb;
970 size_t msg_buff_idx = 0;
971 for (
int i = 0; i < npieces; ++i, msg_buff_idx += MAX_MPI_MESSAGE_COUNT)
973 int tag = (i == (npieces - 1)) ? tags::queue : tags::piece;
975 detail::VectorWindow<char> window;
976 window.begin = &buffer->buffer[msg_buff_idx];
977 window.count = std::min(MAX_MPI_MESSAGE_COUNT, buffer->size() - msg_buff_idx);
979 inflight_sends_.emplace_back();
980 inflight_sends_.back().info = info;
981 inflight_sends_.back().request = comm_.isend(proc, tag, window);
982 inflight_sends_.back().message = buffer;
992 mpi::optional<mpi::status> ostatus = comm_.iprobe(mpi::any_source, mpi::any_tag);
995 InFlightRecv &ir = inflight_recvs_[ostatus->source()];
997 if (ir.info.from == -1)
1000 comm_.recv(ostatus->source(), ostatus->tag(), bb.buffer);
1002 if (ostatus->tag() == tags::piece)
1008 ir.message.buffer.reserve(msg_size);
1013 ir.message.swap(bb);
1018 size_t start_idx = ir.message.buffer.size();
1019 size_t count = ostatus->count<
char>();
1020 ir.message.buffer.resize(start_idx + count);
1022 detail::VectorWindow<char> window;
1023 window.begin = &ir.message.buffer[start_idx];
1024 window.count = count;
1026 comm_.recv(ostatus->source(), ostatus->tag(), window);
1029 if (ostatus->tag() == tags::queue)
1031 size_t size = ir.message.size();
1032 int from = ir.info.from;
1033 int to = ir.info.to;
1036 assert(ir.info.round >= exchange_round_);
1037 IncomingRound *
in = &incoming_[ir.info.round];
1039 bool unload_queue = ((ir.info.round == exchange_round_) ? (block(lid(to)) == 0) : (limit_ != -1)) &&
1040 queue_policy_->unload_incoming(*
this, from, to, size);
1043 log->debug(
"Directly unloading queue {} <- {}", to, from);
1044 external = storage_->put(ir.message);
1048 in->map[to].queues[from].swap(ir.message);
1049 in->map[to].queues[from].reset();
1051 in->map[to].records[from] = QueueRecord(size, external);
1054 ir = InFlightRecv();
1057 ostatus = comm_.iprobe(mpi::any_source, mpi::any_tag);
1066 time_type start = get_time();
1071 incoming_.erase(exchange_round_);
1076 for (OutgoingQueuesMap::iterator it = outgoing_.begin(); it != outgoing_.end(); ++it)
1078 OutgoingQueuesRecord& out = it->second;
1079 if (out.external == -1)
1080 to_send.push_front(it->first);
1082 to_send.push_back(it->first);
1084 log->debug(
"to_send.size(): {}", to_send.size());
1088 int out_queues_limit;
1089 if (limit_ == -1 || size() == 0)
1090 out_queues_limit = to_send.size();
1092 out_queues_limit = std::max((
size_t) 1, to_send.size()/size()*limit_);
1096 comm_exchange(to_send, out_queues_limit);
1099 time_type cur = get_time();
1100 if (cur - start > wait*1000)
1102 log->warn(
"Waiting in flush [{}]: {} - {} out of {}",
1103 comm_.rank(), inflight_sends_.size(), incoming_[exchange_round_].received, expected_);
1107 }
while (!inflight_sends_.empty() || incoming_[exchange_round_].received < expected_ || !to_send.empty());
1111 log->debug(
"Done in flush");
1114 process_collectives();
1119 process_collectives()
1121 auto scoped = prof.scoped(
"collectives");
1123 if (collectives_.empty())
1126 typedef CollectivesList::iterator CollectivesIterator;
1127 std::vector<CollectivesIterator> iters;
1128 std::vector<int> gids;
1129 for (CollectivesMap::iterator cur = collectives_.begin(); cur != collectives_.end(); ++cur)
1131 gids.push_back(cur->first);
1132 iters.push_back(cur->second.begin());
1135 while (iters[0] != collectives_.begin()->second.end())
1138 for (
unsigned j = 1; j < iters.size(); ++j)
1141 iters[0]->update(*iters[j]);
1143 iters[0]->global(comm_);
1145 for (
unsigned j = 1; j < iters.size(); ++j)
1147 iters[j]->copy_from(*iters[0]);
1159 bool success =
false;
1160 for (InFlightSendsList::iterator it = inflight_sends_.begin(); it != inflight_sends_.end(); ++it)
1162 mpi::optional<mpi::status> ostatus = it->request.test();
1166 InFlightSendsList::iterator rm = it;
1168 inflight_sends_.erase(rm);
1176 show_incoming_records()
const
1178 for (IncomingRoundMap::const_iterator rounds_itr = incoming_.begin(); rounds_itr != incoming_.end(); ++rounds_itr)
1180 for (IncomingQueuesMap::const_iterator it = rounds_itr->second.map.begin(); it != rounds_itr->second.map.end(); ++it)
1182 const IncomingQueuesRecords& in_qrs = it->second;
1183 for (InQueueRecords::const_iterator cur = in_qrs.records.begin(); cur != in_qrs.records.end(); ++cur)
1185 const QueueRecord& qr = cur->second;
1186 log->info(
"round: {}, {} <- {}: (size,external) = ({},{})",
1188 it->first, cur->first,
1192 for (IncomingQueues::const_iterator cur = in_qrs.queues.begin(); cur != in_qrs.queues.end(); ++cur)
1194 log->info(
"round: {}, {} <- {}: queue.size() = {}",
1196 it->first, cur->first,
1197 const_cast<IncomingQueuesRecords&>(in_qrs).queues[cur->first].size());
Definition: master.hpp:120
Definition: master.hpp:95
void load(BinaryBuffer &bb, T &x)
Loads x from bb by calling diy::Serialization<T>::load(bb,x).
Definition: serialization.hpp:106
void load_back(BinaryBuffer &bb, T &x)
Supports only binary data copying (meant for simple footers).
Definition: serialization.hpp:120
Definition: master.hpp:356
Definition: master.hpp:146
Definition: storage.hpp:41
Definition: proxy.hpp:134
void save(BinaryBuffer &bb, const T &x)
Saves x to bb by calling diy::Serialization<T>::save(bb,x).
Definition: serialization.hpp:102
int gid(int i) const
return gid of the i-th block
Definition: master.hpp:219
Definition: master.hpp:384
void foreach_(const Callback< Block > &f, const Skip &s=NeverSkip())
call f with every block
Definition: master.hpp:703
void in(const RegularLink< Bounds > &link, const Point &p, OutIter out, const Bounds &domain)
Finds the neighbor(s) containing the target point.
Definition: pick.hpp:102
Definition: master.hpp:41
int add(int gid, void *b, Link *l)
add a block
Definition: master.hpp:658
Definition: master.hpp:35
Simple wrapper around MPI_Comm.
Definition: communicator.hpp:8
Communication proxy, used for enqueueing and dequeueing items for future exchange.
Definition: proxy.hpp:8
Definition: serialization.hpp:26
Definition: no-thread.hpp:27
Definition: master.hpp:353
Definition: master.hpp:72
Definition: master.hpp:333
Definition: master.hpp:47
Master(mpi::communicator comm, int threads=1, int limit=-1, CreateBlock create=0, DestroyBlock destroy=0, ExternalStorage *storage=0, SaveBlock save=0, LoadBlock load=0, QueuePolicy *q_policy=new QueueSizePolicy(4096))
The main DIY object.
Definition: master.hpp:164
const mpi::communicator & communicator() const
return the MPI communicator
Definition: master.hpp:212
void * release(int i)
release ownership of the block
Definition: master.hpp:678
Definition: request.hpp:5
Definition: master.hpp:136
Definition: master.hpp:55
bool local(int gid) const
whether the block with global id gid is local
Definition: master.hpp:223
Definition: master.hpp:89
void exchange()
exchange the queues between all the blocks (collective operation)
Definition: master.hpp:798
Definition: master.hpp:104
Move queues out of core if their size exceeds a parameter given in the constructor.
Definition: master.hpp:80
unsigned size() const
return the number of local blocks
Definition: master.hpp:233
Definition: master.hpp:131
mpi::communicator & communicator()
return the MPI communicator
Definition: master.hpp:214
Definition: no-thread.hpp:9
int lid(int gid) const
return the local id of the local block with global id gid, or -1 if not local
Definition: master.hpp:221