File indexing completed on 2025-01-18 09:40:59
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef BOOST_MPI_NONBLOCKING_HPP
0013 #define BOOST_MPI_NONBLOCKING_HPP
0014
0015 #include <boost/mpi/config.hpp>
0016 #include <vector>
0017 #include <iterator> // for std::iterator_traits
0018 #include <boost/optional.hpp>
0019 #include <utility> // for std::pair
0020 #include <algorithm> // for iter_swap, reverse
0021 #include <boost/static_assert.hpp>
0022 #include <boost/mpi/request.hpp>
0023 #include <boost/mpi/status.hpp>
0024 #include <boost/mpi/exception.hpp>
0025
0026 namespace boost { namespace mpi {
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046 template<typename ForwardIterator>
0047 std::pair<status, ForwardIterator>
0048 wait_any(ForwardIterator first, ForwardIterator last)
0049 {
0050 using std::advance;
0051
0052 BOOST_ASSERT(first != last);
0053
0054 typedef typename std::iterator_traits<ForwardIterator>::difference_type
0055 difference_type;
0056
0057 bool all_trivial_requests = true;
0058 difference_type n = 0;
0059 ForwardIterator current = first;
0060 while (true) {
0061
0062 if (current->active()) {
0063 optional<status> result = current->test();
0064 if (bool(result)) {
0065 return std::make_pair(*result, current);
0066 }
0067 }
0068
0069
0070
0071
0072
0073
0074
0075 all_trivial_requests = all_trivial_requests && current->trivial();
0076
0077
0078 ++n;
0079 if (++current == last) {
0080
0081
0082
0083 if (all_trivial_requests) {
0084 std::vector<MPI_Request> requests;
0085 requests.reserve(n);
0086 for (current = first; current != last; ++current) {
0087 requests.push_back(*current->trivial());
0088 }
0089
0090
0091 int index;
0092 status stat;
0093 BOOST_MPI_CHECK_RESULT(MPI_Waitany,
0094 (n, detail::c_data(requests), &index, &stat.m_status));
0095
0096
0097
0098 if (index == MPI_UNDEFINED)
0099 boost::throw_exception(exception("MPI_Waitany", MPI_ERR_REQUEST));
0100
0101
0102 current = first;
0103 advance(current, index);
0104 *current->trivial() = requests[index];
0105 return std::make_pair(stat, current);
0106 }
0107
0108
0109
0110 n = 0;
0111 current = first;
0112 all_trivial_requests = true;
0113 }
0114 }
0115
0116
0117 BOOST_ASSERT(false);
0118 }
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140 template<typename ForwardIterator>
0141 optional<std::pair<status, ForwardIterator> >
0142 test_any(ForwardIterator first, ForwardIterator last)
0143 {
0144 while (first != last) {
0145
0146 if (optional<status> result = first->test()) {
0147 return std::make_pair(*result, first);
0148 }
0149 ++first;
0150 }
0151
0152
0153 return optional<std::pair<status, ForwardIterator> >();
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 template<typename ForwardIterator, typename OutputIterator>
0179 OutputIterator
0180 wait_all(ForwardIterator first, ForwardIterator last, OutputIterator out)
0181 {
0182 typedef typename std::iterator_traits<ForwardIterator>::difference_type
0183 difference_type;
0184
0185 using std::distance;
0186
0187 difference_type num_outstanding_requests = distance(first, last);
0188
0189 std::vector<status> results(num_outstanding_requests);
0190 std::vector<bool> completed(num_outstanding_requests);
0191
0192 while (num_outstanding_requests > 0) {
0193 bool all_trivial_requests = true;
0194 difference_type idx = 0;
0195 for (ForwardIterator current = first; current != last; ++current, ++idx) {
0196 if (!completed[idx]) {
0197 if (!current->active()) {
0198 completed[idx] = true;
0199 --num_outstanding_requests;
0200 } else if (optional<status> stat = current->test()) {
0201
0202 results[idx] = *stat;
0203 completed[idx] = true;
0204 --num_outstanding_requests;
0205 all_trivial_requests = false;
0206 } else {
0207
0208
0209
0210 all_trivial_requests = all_trivial_requests && current->trivial();
0211 }
0212 }
0213 }
0214
0215
0216
0217
0218 if (all_trivial_requests
0219 && num_outstanding_requests == (difference_type)results.size()) {
0220 std::vector<MPI_Request> requests;
0221 requests.reserve(num_outstanding_requests);
0222 for (ForwardIterator current = first; current != last; ++current)
0223 requests.push_back(*current->trivial());
0224
0225
0226 std::vector<MPI_Status> stats(num_outstanding_requests);
0227 BOOST_MPI_CHECK_RESULT(MPI_Waitall,
0228 (num_outstanding_requests, detail::c_data(requests),
0229 detail::c_data(stats)));
0230
0231 for (std::vector<MPI_Status>::iterator i = stats.begin();
0232 i != stats.end(); ++i, ++out) {
0233 status stat;
0234 stat.m_status = *i;
0235 *out = stat;
0236 }
0237
0238 return out;
0239 }
0240
0241 all_trivial_requests = false;
0242 }
0243
0244 return std::copy(results.begin(), results.end(), out);
0245 }
0246
0247
0248
0249
0250 template<typename ForwardIterator>
0251 void
0252 wait_all(ForwardIterator first, ForwardIterator last)
0253 {
0254 typedef typename std::iterator_traits<ForwardIterator>::difference_type
0255 difference_type;
0256
0257 using std::distance;
0258
0259 difference_type num_outstanding_requests = distance(first, last);
0260
0261 std::vector<bool> completed(num_outstanding_requests, false);
0262
0263 while (num_outstanding_requests > 0) {
0264 bool all_trivial_requests = true;
0265
0266 difference_type idx = 0;
0267 for (ForwardIterator current = first; current != last; ++current, ++idx) {
0268 if (!completed[idx]) {
0269 if (!current->active()) {
0270 completed[idx] = true;
0271 --num_outstanding_requests;
0272 } else if (optional<status> stat = current->test()) {
0273
0274 completed[idx] = true;
0275 --num_outstanding_requests;
0276 all_trivial_requests = false;
0277 } else {
0278
0279
0280
0281 all_trivial_requests = all_trivial_requests && current->trivial();
0282 }
0283 }
0284 }
0285
0286
0287
0288
0289 if (all_trivial_requests
0290 && num_outstanding_requests == (difference_type)completed.size()) {
0291 std::vector<MPI_Request> requests;
0292 requests.reserve(num_outstanding_requests);
0293 for (ForwardIterator current = first; current != last; ++current)
0294 requests.push_back(*current->trivial());
0295
0296
0297 BOOST_MPI_CHECK_RESULT(MPI_Waitall,
0298 (num_outstanding_requests, detail::c_data(requests),
0299 MPI_STATUSES_IGNORE));
0300
0301
0302 num_outstanding_requests = 0;
0303 }
0304 }
0305 }
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338 template<typename ForwardIterator, typename OutputIterator>
0339 optional<OutputIterator>
0340 test_all(ForwardIterator first, ForwardIterator last, OutputIterator out)
0341 {
0342 std::vector<MPI_Request> requests;
0343 for (; first != last; ++first) {
0344
0345
0346 if (!first->trivial()) {
0347 return optional<OutputIterator>();
0348 }
0349 requests.push_back(*first->trivial());
0350 }
0351
0352 int flag = 0;
0353 int n = requests.size();
0354 std::vector<MPI_Status> stats(n);
0355 BOOST_MPI_CHECK_RESULT(MPI_Testall, (n, detail::c_data(requests), &flag, detail::c_data(stats)));
0356 if (flag) {
0357 for (int i = 0; i < n; ++i, ++out) {
0358 status stat;
0359 stat.m_status = stats[i];
0360 *out = stat;
0361 }
0362 return out;
0363 } else {
0364 return optional<OutputIterator>();
0365 }
0366 }
0367
0368
0369
0370
0371 template<typename ForwardIterator>
0372 bool
0373 test_all(ForwardIterator first, ForwardIterator last)
0374 {
0375 std::vector<MPI_Request> requests;
0376 for (; first != last; ++first) {
0377
0378
0379 if (!first->trivial()) {
0380 return false;
0381 }
0382 requests.push_back(*first->trivial());
0383 }
0384
0385 int flag = 0;
0386 int n = requests.size();
0387 BOOST_MPI_CHECK_RESULT(MPI_Testall,
0388 (n, detail::c_data(requests), &flag, MPI_STATUSES_IGNORE));
0389 return flag != 0;
0390 }
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418 template<typename BidirectionalIterator, typename OutputIterator>
0419 std::pair<OutputIterator, BidirectionalIterator>
0420 wait_some(BidirectionalIterator first, BidirectionalIterator last,
0421 OutputIterator out)
0422 {
0423 using std::advance;
0424
0425 if (first == last)
0426 return std::make_pair(out, first);
0427
0428 typedef typename std::iterator_traits<BidirectionalIterator>::difference_type
0429 difference_type;
0430
0431 bool all_trivial_requests = true;
0432 difference_type n = 0;
0433 BidirectionalIterator current = first;
0434 BidirectionalIterator start_of_completed = last;
0435 while (true) {
0436
0437 if (optional<status> result = current->test()) {
0438 using std::iter_swap;
0439
0440
0441 *out++ = *result;
0442
0443
0444 --start_of_completed;
0445
0446 if (current == start_of_completed) {
0447
0448
0449
0450
0451 std::reverse(start_of_completed, last);
0452 return std::make_pair(out, start_of_completed);
0453 }
0454
0455
0456
0457 iter_swap(current, start_of_completed);
0458
0459 continue;
0460 }
0461
0462
0463
0464
0465 all_trivial_requests = all_trivial_requests && current->trivial();
0466
0467
0468 ++n;
0469 if (++current == start_of_completed) {
0470 if (start_of_completed != last) {
0471
0472
0473
0474 std::reverse(start_of_completed, last);
0475 return std::make_pair(out, start_of_completed);
0476 }
0477
0478
0479
0480
0481 if (all_trivial_requests) {
0482 std::vector<MPI_Request> requests;
0483 std::vector<int> indices(n);
0484 std::vector<MPI_Status> stats(n);
0485 requests.reserve(n);
0486 for (current = first; current != last; ++current)
0487 requests.push_back(*current->trivial());
0488
0489
0490 int num_completed;
0491 BOOST_MPI_CHECK_RESULT(MPI_Waitsome,
0492 (n, detail::c_data(requests), &num_completed, detail::c_data(indices),
0493 detail::c_data(stats)));
0494
0495
0496
0497 int current_offset = 0;
0498 current = first;
0499 for (int index = 0; index < num_completed; ++index, ++out) {
0500 using std::iter_swap;
0501
0502
0503 advance(current, indices[index] - current_offset);
0504 current_offset = indices[index];
0505
0506
0507 status stat;
0508 stat.m_status = stats[index];
0509 *out = stat;
0510
0511
0512
0513 *current->trivial() = requests[indices[index]];
0514 --start_of_completed;
0515 iter_swap(current, start_of_completed);
0516 }
0517
0518
0519
0520
0521 std::reverse(start_of_completed, last);
0522 return std::make_pair(out, start_of_completed);
0523 }
0524
0525
0526
0527 n = 0;
0528 current = first;
0529 }
0530 }
0531
0532
0533 BOOST_ASSERT(false);
0534 }
0535
0536
0537
0538
0539 template<typename BidirectionalIterator>
0540 BidirectionalIterator
0541 wait_some(BidirectionalIterator first, BidirectionalIterator last)
0542 {
0543 using std::advance;
0544
0545 if (first == last)
0546 return first;
0547
0548 typedef typename std::iterator_traits<BidirectionalIterator>::difference_type
0549 difference_type;
0550
0551 bool all_trivial_requests = true;
0552 difference_type n = 0;
0553 BidirectionalIterator current = first;
0554 BidirectionalIterator start_of_completed = last;
0555 while (true) {
0556
0557 if (optional<status> result = current->test()) {
0558 using std::iter_swap;
0559
0560
0561 --start_of_completed;
0562
0563
0564
0565 if (current == start_of_completed)
0566 return start_of_completed;
0567
0568
0569
0570 iter_swap(current, start_of_completed);
0571
0572 continue;
0573 }
0574
0575
0576
0577
0578 all_trivial_requests = all_trivial_requests && current->trivial();
0579
0580
0581 ++n;
0582 if (++current == start_of_completed) {
0583
0584 if (start_of_completed != last)
0585 return start_of_completed;
0586
0587
0588
0589
0590 if (all_trivial_requests) {
0591 std::vector<MPI_Request> requests;
0592 std::vector<int> indices(n);
0593 requests.reserve(n);
0594 for (current = first; current != last; ++current)
0595 requests.push_back(*current->trivial());
0596
0597
0598 int num_completed;
0599 BOOST_MPI_CHECK_RESULT(MPI_Waitsome,
0600 (n, detail::c_data(requests), &num_completed, detail::c_data(indices),
0601 MPI_STATUSES_IGNORE));
0602
0603
0604
0605 int current_offset = 0;
0606 current = first;
0607 for (int index = 0; index < num_completed; ++index) {
0608 using std::iter_swap;
0609
0610
0611 advance(current, indices[index] - current_offset);
0612 current_offset = indices[index];
0613
0614
0615
0616 *current->trivial() = requests[indices[index]];
0617 --start_of_completed;
0618 iter_swap(current, start_of_completed);
0619 }
0620
0621
0622 return start_of_completed;
0623 }
0624
0625
0626
0627 n = 0;
0628 current = first;
0629 }
0630 }
0631
0632
0633 BOOST_ASSERT(false);
0634 }
0635
0636
0637
0638
0639
0640
0641
0642
0643
0644
0645
0646
0647
0648
0649
0650
0651
0652
0653
0654
0655
0656
0657
0658
0659
0660
0661
0662
0663
0664 template<typename BidirectionalIterator, typename OutputIterator>
0665 std::pair<OutputIterator, BidirectionalIterator>
0666 test_some(BidirectionalIterator first, BidirectionalIterator last,
0667 OutputIterator out)
0668 {
0669 BidirectionalIterator current = first;
0670 BidirectionalIterator start_of_completed = last;
0671 while (current != start_of_completed) {
0672
0673 if (optional<status> result = current->test()) {
0674 using std::iter_swap;
0675
0676
0677 *out++ = *result;
0678
0679
0680 --start_of_completed;
0681
0682
0683
0684 iter_swap(current, start_of_completed);
0685
0686 continue;
0687 }
0688
0689
0690 ++current;
0691 }
0692
0693
0694
0695 std::reverse(start_of_completed, last);
0696 return std::make_pair(out, start_of_completed);
0697 }
0698
0699
0700
0701
0702 template<typename BidirectionalIterator>
0703 BidirectionalIterator
0704 test_some(BidirectionalIterator first, BidirectionalIterator last)
0705 {
0706 BidirectionalIterator current = first;
0707 BidirectionalIterator start_of_completed = last;
0708 while (current != start_of_completed) {
0709
0710 if (optional<status> result = current->test()) {
0711 using std::iter_swap;
0712
0713
0714 --start_of_completed;
0715
0716
0717
0718 iter_swap(current, start_of_completed);
0719
0720 continue;
0721 }
0722
0723
0724 ++current;
0725 }
0726
0727 return start_of_completed;
0728 }
0729
0730 } }
0731
0732
0733 #endif