File indexing completed on 2025-01-18 09:50:15
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <boost/property_map/property_map.hpp>
0016
0017 #ifndef BOOST_PARALLEL_DISTRIBUTED_PROPERTY_MAP_HPP
0018 #define BOOST_PARALLEL_DISTRIBUTED_PROPERTY_MAP_HPP
0019
0020 #include <boost/assert.hpp>
0021 #include <boost/type_traits/is_base_and_derived.hpp>
0022 #include <boost/shared_ptr.hpp>
0023 #include <boost/weak_ptr.hpp>
0024 #include <boost/optional.hpp>
0025 #include <boost/property_map/parallel/process_group.hpp>
0026 #include <boost/function/function1.hpp>
0027 #include <vector>
0028 #include <set>
0029 #include <boost/property_map/parallel/basic_reduce.hpp>
0030 #include <boost/property_map/parallel/detail/untracked_pair.hpp>
0031 #include <boost/type_traits/is_same.hpp>
0032 #include <boost/property_map/parallel/local_property_map.hpp>
0033 #include <map>
0034 #include <boost/version.hpp>
0035 #include <boost/property_map/parallel/unsafe_serialize.hpp>
0036 #include <boost/multi_index_container.hpp>
0037 #include <boost/multi_index/hashed_index.hpp>
0038 #include <boost/multi_index/member.hpp>
0039 #include <boost/multi_index/sequenced_index.hpp>
0040
0041
0042 #include <boost/serialization/utility.hpp>
0043
0044 namespace boost { namespace parallel {
0045
0046 namespace detail {
0047
0048
0049
0050
0051 template<bool IsLvaluePropertyMap>
0052 struct make_nonlvalue_property_map
0053 {
0054 template<typename T> struct apply { typedef T type; };
0055 };
0056
0057 template<>
0058 struct make_nonlvalue_property_map<true>
0059 {
0060 template<typename>
0061 struct apply
0062 {
0063 typedef read_write_property_map_tag type;
0064 };
0065 };
0066
0067
0068
0069
0070
0071
0072
0073
0074 template<bool IsLvaluePropertyMap>
0075 struct maybe_put_in_lvalue_pm
0076 {
0077 template<typename PropertyMap, typename Key, typename Value>
0078 static inline void
0079 do_put(PropertyMap, const Key&, const Value&)
0080 { BOOST_ASSERT(false); }
0081 };
0082
0083 template<>
0084 struct maybe_put_in_lvalue_pm<true>
0085 {
0086 template<typename PropertyMap, typename Key, typename Value>
0087 static inline void
0088 do_put(PropertyMap pm, const Key& key, const Value& value)
0089 {
0090 using boost::put;
0091
0092 put(pm, key, value);
0093 }
0094 };
0095
0096 template<typename PropertyMap, typename Key, typename Value>
0097 inline void
0098 maybe_put_impl(PropertyMap pm, const Key& key, const Value& value,
0099 writable_property_map_tag)
0100 {
0101 using boost::put;
0102
0103 put(pm, key, value);
0104 }
0105
0106 template<typename PropertyMap, typename Key, typename Value>
0107 inline void
0108 maybe_put_impl(PropertyMap pm, const Key& key, const Value& value,
0109 lvalue_property_map_tag)
0110 {
0111 typedef typename property_traits<PropertyMap>::value_type value_type;
0112 typedef typename property_traits<PropertyMap>::reference reference;
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123 typedef is_same<const value_type&, reference> is_constant;
0124
0125 maybe_put_in_lvalue_pm<(!is_constant::value)>::do_put(pm, key, value);
0126 }
0127
0128 template<typename PropertyMap, typename Key, typename Value>
0129 inline void
0130 maybe_put_impl(PropertyMap, const Key&, const Value&, ...)
0131 { BOOST_ASSERT(false); }
0132
0133 template<typename PropertyMap, typename Key, typename Value>
0134 inline void
0135 maybe_put(PropertyMap pm, const Key& key, const Value& value)
0136 {
0137 maybe_put_impl(pm, key, value,
0138 typename property_traits<PropertyMap>::category());
0139 }
0140 }
0141
0142
0143 enum consistency_model {
0144 cm_forward = 1 << 0,
0145 cm_backward = 1 << 1,
0146 cm_bidirectional = cm_forward | cm_backward,
0147 cm_flush = 1 << 2,
0148 cm_reset = 1 << 3,
0149 cm_clear = 1 << 4
0150 };
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210 template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
0211 class distributed_property_map
0212 {
0213 public:
0214
0215 typedef typename property_traits<GlobalMap>::key_type key_type;
0216
0217
0218 typedef typename property_traits<StorageMap>::value_type value_type;
0219 typedef typename property_traits<StorageMap>::reference reference;
0220 typedef ProcessGroup process_group_type;
0221
0222 private:
0223 typedef distributed_property_map self_type;
0224 typedef typename property_traits<StorageMap>::category local_category;
0225 typedef typename property_traits<StorageMap>::key_type local_key_type;
0226 typedef typename property_traits<GlobalMap>::value_type owner_local_pair;
0227 typedef typename ProcessGroup::process_id_type process_id_type;
0228
0229 enum property_map_messages {
0230
0231
0232
0233 property_map_put,
0234
0235
0236
0237
0238
0239 property_map_get,
0240
0241
0242
0243
0244
0245
0246 property_map_multiget,
0247
0248
0249
0250
0251
0252 property_map_multiget_reply,
0253
0254
0255
0256
0257
0258 property_map_multiput
0259 };
0260
0261
0262
0263 template<typename First,typename Second>
0264 class pair_first_extractor {
0265 typedef std::pair<First,Second> value_type;
0266
0267 public:
0268 typedef First result_type;
0269 const result_type& operator()(const value_type& x) const {
0270 return x.first;
0271 }
0272
0273 result_type& operator()(value_type& x) const {
0274 return x.first;
0275 }
0276 };
0277
0278 public:
0279
0280 typedef multi_index::multi_index_container<
0281 std::pair<key_type, value_type>,
0282 multi_index::indexed_by<
0283 multi_index::sequenced<>,
0284 multi_index::hashed_unique<
0285 pair_first_extractor<key_type, value_type>
0286 >
0287 >
0288 > ghost_cells_type;
0289
0290
0291 typedef typename ghost_cells_type::iterator iterator;
0292
0293
0294 typedef typename ghost_cells_type::template nth_index<1>::type
0295 ghost_cells_key_index_type;
0296
0297
0298 typedef typename ghost_cells_key_index_type::iterator key_iterator;
0299
0300
0301
0302
0303
0304 typedef typename detail::make_nonlvalue_property_map<
0305 (is_base_and_derived<lvalue_property_map_tag, local_category>::value
0306 || is_same<lvalue_property_map_tag, local_category>::value)>
0307 ::template apply<local_category>::type category;
0308
0309
0310
0311
0312
0313
0314 distributed_property_map() {}
0315
0316
0317
0318
0319
0320
0321
0322 distributed_property_map(const ProcessGroup& pg, const GlobalMap& global,
0323 const StorageMap& pm)
0324 : data(new data_t(pg, global, pm, basic_reduce<value_type>(), false))
0325 {
0326 typedef handle_message<basic_reduce<value_type> > Handler;
0327
0328 data->ghost_cells.reset(new ghost_cells_type());
0329 Handler handler(data);
0330 data->process_group.replace_handler(handler, true);
0331 data->process_group.template get_receiver<Handler>()
0332 ->setup_triggers(data->process_group);
0333 }
0334
0335
0336
0337
0338
0339
0340 template<typename Reduce>
0341 distributed_property_map(const ProcessGroup& pg, const GlobalMap& global,
0342 const StorageMap& pm,
0343 const Reduce& reduce);
0344
0345 ~distributed_property_map();
0346
0347
0348 template<typename Reduce>
0349 void set_reduce(const Reduce& reduce);
0350
0351
0352 void set_consistency_model(int model);
0353
0354
0355 int get_consistency_model() const { return data->model; }
0356
0357
0358
0359 void set_max_ghost_cells(std::size_t max_ghost_cells);
0360
0361
0362 void clear();
0363
0364
0365 void reset();
0366
0367
0368 void flush();
0369
0370 reference operator[](const key_type& key) const
0371 {
0372 owner_local_pair p = get(data->global, key);
0373
0374 if (p.first == process_id(data->process_group)) {
0375 return data->storage[p.second];
0376 } else {
0377 return cell(key);
0378 }
0379 }
0380
0381 process_group_type process_group() const
0382 {
0383 return data->process_group.base();
0384 }
0385
0386 StorageMap& base() { return data->storage; }
0387 const StorageMap& base() const { return data->storage; }
0388
0389
0390
0391
0392
0393 void
0394 request_put(process_id_type p, const key_type& k, const value_type& v) const
0395 {
0396 send(data->process_group, p, property_map_put,
0397 boost::parallel::detail::make_untracked_pair(k, v));
0398 }
0399
0400
0401
0402
0403 value_type& cell(const key_type& k, bool request_if_missing = true) const;
0404
0405
0406
0407
0408 void do_synchronize();
0409
0410 const GlobalMap& global() const { return data->global; }
0411 GlobalMap& global() { return data->global; }
0412
0413 struct data_t
0414 {
0415 data_t(const ProcessGroup& pg, const GlobalMap& global,
0416 const StorageMap& pm, const function1<value_type, key_type>& dv,
0417 bool has_default_resolver)
0418 : process_group(pg), global(global), storage(pm),
0419 ghost_cells(), max_ghost_cells(1000000), get_default_value(dv),
0420 has_default_resolver(has_default_resolver), model(cm_forward) { }
0421
0422
0423 ProcessGroup process_group;
0424
0425
0426
0427 GlobalMap global;
0428
0429
0430 StorageMap storage;
0431
0432
0433 shared_ptr<ghost_cells_type> ghost_cells;
0434
0435
0436
0437
0438 std::size_t max_ghost_cells;
0439
0440
0441
0442 function1<value_type, key_type> get_default_value;
0443
0444
0445
0446
0447 bool has_default_resolver;
0448
0449
0450 int model;
0451
0452
0453
0454
0455 void (data_t::*reset)();
0456
0457
0458 void clear();
0459
0460
0461 void flush();
0462
0463
0464
0465 void refresh_ghost_cells();
0466
0467 private:
0468 template<typename Resolver> void do_reset();
0469
0470 friend class distributed_property_map;
0471 };
0472 friend struct data_t;
0473
0474 shared_ptr<data_t> data;
0475
0476 private:
0477
0478
0479 void prune_ghost_cells() const;
0480
0481
0482
0483
0484
0485
0486 template<typename Reduce>
0487 struct handle_message
0488 {
0489 explicit handle_message(const shared_ptr<data_t>& data,
0490 const Reduce& reduce = Reduce())
0491 : data_ptr(data), reduce(reduce) { }
0492
0493 void operator()(process_id_type source, int tag);
0494
0495
0496 void
0497 handle_put(int source, int tag,
0498 const boost::parallel::detail::untracked_pair<key_type, value_type>& data,
0499 trigger_receive_context);
0500
0501 value_type
0502 handle_get(int source, int tag, const key_type& data,
0503 trigger_receive_context);
0504
0505 void
0506 handle_multiget(int source, int tag,
0507 const std::vector<key_type>& data,
0508 trigger_receive_context);
0509
0510 void
0511 handle_multiget_reply
0512 (int source, int tag,
0513 const std::vector<boost::parallel::detail::untracked_pair<key_type, value_type> >& msg,
0514 trigger_receive_context);
0515
0516 void
0517 handle_multiput
0518 (int source, int tag,
0519 const std::vector<unsafe_pair<local_key_type, value_type> >& data,
0520 trigger_receive_context);
0521
0522 void setup_triggers(process_group_type& pg);
0523
0524 private:
0525 weak_ptr<data_t> data_ptr;
0526 Reduce reduce;
0527 };
0528
0529
0530
0531 struct on_synchronize
0532 {
0533 explicit on_synchronize(const shared_ptr<data_t>& data) : data_ptr(data) { }
0534
0535 void operator()();
0536
0537 private:
0538 weak_ptr<data_t> data_ptr;
0539 };
0540 };
0541
0542
0543
0544
0545 #define PBGL_DISTRIB_PMAP \
0546 distributed_property_map<ProcessGroup, GlobalMap, StorageMap>
0547
0548
0549
0550 template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
0551 inline void
0552 request(const PBGL_DISTRIB_PMAP& pm,
0553 typename PBGL_DISTRIB_PMAP::key_type const& key)
0554 {
0555 if (get(pm.data->global, key).first != process_id(pm.data->process_group))
0556 pm.cell(key, false);
0557 }
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569 template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
0570 inline
0571 typename PBGL_DISTRIB_PMAP::value_type
0572 get(const PBGL_DISTRIB_PMAP& pm,
0573 typename PBGL_DISTRIB_PMAP::key_type const& key)
0574 {
0575 using boost::get;
0576
0577 typename property_traits<GlobalMap>::value_type p =
0578 get(pm.data->global, key);
0579
0580 if (p.first == process_id(pm.data->process_group)) {
0581 return get(pm.data->storage, p.second);
0582 } else {
0583 return pm.cell(key);
0584 }
0585 }
0586
0587
0588
0589
0590
0591
0592
0593
0594
0595
0596
0597 template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
0598 void
0599 put(const PBGL_DISTRIB_PMAP& pm,
0600 typename PBGL_DISTRIB_PMAP::key_type const & key,
0601 typename PBGL_DISTRIB_PMAP::value_type const & value)
0602 {
0603 using boost::put;
0604
0605 typename property_traits<GlobalMap>::value_type p =
0606 get(pm.data->global, key);
0607
0608 if (p.first == process_id(pm.data->process_group)) {
0609 put(pm.data->storage, p.second, value);
0610 } else {
0611 if (pm.data->model & cm_forward)
0612 pm.request_put(p.first, key, value);
0613
0614 pm.cell(key, false) = value;
0615 }
0616 }
0617
0618
0619
0620
0621
0622
0623
0624
0625 template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
0626 void
0627 local_put(const PBGL_DISTRIB_PMAP& pm,
0628 typename PBGL_DISTRIB_PMAP::key_type const & key,
0629 typename PBGL_DISTRIB_PMAP::value_type const & value)
0630 {
0631 using boost::put;
0632
0633 typename property_traits<GlobalMap>::value_type p =
0634 get(pm.data->global, key);
0635
0636 if (p.first == process_id(pm.data->process_group))
0637 put(pm.data->storage, p.second, value);
0638 else pm.cell(key, false) = value;
0639 }
0640
0641
0642
0643 template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
0644 inline void
0645 cache(const PBGL_DISTRIB_PMAP& pm,
0646 typename PBGL_DISTRIB_PMAP::key_type const & key,
0647 typename PBGL_DISTRIB_PMAP::value_type const & value)
0648 {
0649 typename ProcessGroup::process_id_type id = get(pm.data->global, key).first;
0650
0651 if (id != process_id(pm.data->process_group)) pm.cell(key, false) = value;
0652 }
0653
0654
0655 template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
0656 void
0657 synchronize(PBGL_DISTRIB_PMAP& pm)
0658 {
0659 pm.do_synchronize();
0660 }
0661
0662
0663 template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
0664 inline distributed_property_map<ProcessGroup, GlobalMap, StorageMap>
0665 make_distributed_property_map(const ProcessGroup& pg, GlobalMap global,
0666 StorageMap storage)
0667 {
0668 typedef distributed_property_map<ProcessGroup, GlobalMap, StorageMap>
0669 result_type;
0670 return result_type(pg, global, storage);
0671 }
0672
0673
0674
0675
0676 template<typename ProcessGroup, typename GlobalMap, typename StorageMap,
0677 typename Reduce>
0678 inline distributed_property_map<ProcessGroup, GlobalMap, StorageMap>
0679 make_distributed_property_map(const ProcessGroup& pg, GlobalMap global,
0680 StorageMap storage, Reduce reduce)
0681 {
0682 typedef distributed_property_map<ProcessGroup, GlobalMap, StorageMap>
0683 result_type;
0684 return result_type(pg, global, storage, reduce);
0685 }
0686
0687 } }
0688
0689 #include <boost/property_map/parallel/impl/distributed_property_map.ipp>
0690
0691 #undef PBGL_DISTRIB_PMAP
0692
0693 #endif