UPstreamRequest.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011 OpenFOAM Foundation
9  Copyright (C) 2023 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "UPstreamWrapping.H"
30 #include "PstreamGlobals.H"
31 #include "profilingPstream.H"
32 
33 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
34 
36 :
37  UPstream::Request(MPI_REQUEST_NULL)
38 {}
39 
40 
41 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
42 
44 {
45  return MPI_REQUEST_NULL != PstreamUtils::Cast::to_mpi(*this);
46 }
47 
48 
50 {
51  *this = UPstream::Request(MPI_REQUEST_NULL);
52 }
53 
54 
55 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
56 
57 // Foam::UPstream::Request
58 // Foam::UPstream::Request::lookup(const label req)
59 // {
60 // if (req < 0 || req >= PstreamGlobals::outstandingRequests_.size())
61 // {
62 // WarningInFunction
63 // << "Illegal request " << req << nl
64 // << "Should be within range [0,"
65 // << PstreamGlobals::outstandingRequests_.size()
66 // << ')' << endl;
67 //
68 // return UPstream::Communicator(MPI_REQUEST_NULL);
69 // }
70 //
71 // return UPstream::Request(PstreamGlobals::outstandingRequests_[req]);
72 // }
73 
74 
75 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
76 
78 {
80 }
81 
82 
83 void Foam::UPstream::resetRequests(const label n)
84 {
85  if (n >= 0 && n < PstreamGlobals::outstandingRequests_.size())
86  {
88  }
89 }
90 
91 
92 void Foam::UPstream::addRequest(UPstream::Request& req)
93 {
94  // No-op for non-parallel
95  if (!UPstream::parRun())
96  {
97  return;
98  }
99 
100  // Transcribe as a MPI_Request
102  (
104  );
105 
106  // Invalidate parameter
107  req = UPstream::Request(MPI_REQUEST_NULL);
108 }
109 
110 
111 void Foam::UPstream::cancelRequest(const label i)
112 {
113  // No-op for non-parallel, or out-of-range (eg, placeholder indices)
114  if
115  (
117  || i < 0
119  )
120  {
121  return;
122  }
123 
124  {
125  auto& request = PstreamGlobals::outstandingRequests_[i];
126  if (MPI_REQUEST_NULL != request) // Active handle is mandatory
127  {
128  MPI_Cancel(&request);
129  MPI_Request_free(&request); //<- Sets to MPI_REQUEST_NULL
130  }
131  }
132 }
133 
134 
135 void Foam::UPstream::cancelRequest(UPstream::Request& req)
136 {
137  // No-op for non-parallel
138  if (!UPstream::parRun())
139  {
140  return;
141  }
142 
143  {
144  MPI_Request request = PstreamUtils::Cast::to_mpi(req);
145  if (MPI_REQUEST_NULL != request) // Active handle is mandatory
146  {
147  MPI_Cancel(&request);
148  MPI_Request_free(&request);
149  }
150  req = UPstream::Request(MPI_REQUEST_NULL); // Now inactive
151  }
152 }
153 
154 
155 void Foam::UPstream::cancelRequests(UList<UPstream::Request>& requests)
156 {
157  // No-op for non-parallel
158  if (!UPstream::parRun())
159  {
160  return;
161  }
162 
163  for (auto& req : requests)
164  {
165  MPI_Request request = PstreamUtils::Cast::to_mpi(req);
166  if (MPI_REQUEST_NULL != request) // Active handle is mandatory
167  {
168  MPI_Cancel(&request);
169  MPI_Request_free(&request);
170  }
171  req = UPstream::Request(MPI_REQUEST_NULL); // Now inactive
172  }
173 }
174 
175 
176 void Foam::UPstream::removeRequests(const label pos, label len)
177 {
178  // No-op for non-parallel, no pending requests or out-of-range
179  if
180  (
182  || (pos < 0 || pos >= PstreamGlobals::outstandingRequests_.size())
183  || !len
184  )
185  {
186  return;
187  }
188 
190 
191  // Apply range-checking on slice with (len < 0) behaving like npos
192  // (ie, the rest of the list)
193  if (len >= 0 && len < count)
194  {
195  // A non-trailing slice
196  count = len;
197  }
198  // Have count >= 1
199 
200  const labelRange range(pos, count);
201 
202  for (const label i : range)
203  {
204  auto& request = PstreamGlobals::outstandingRequests_[i];
205  if (MPI_REQUEST_NULL != request) // Active handle is mandatory
206  {
207  MPI_Cancel(&request);
208  MPI_Request_free(&request); //<- Sets to MPI_REQUEST_NULL
209  }
210  }
211 
212  // Remove from list of outstanding requests and move down
214 }
215 
216 
217 void Foam::UPstream::freeRequest(UPstream::Request& req)
218 {
219  // No-op for non-parallel
220  if (!UPstream::parRun())
221  {
222  return;
223  }
224 
225  {
226  MPI_Request request = PstreamUtils::Cast::to_mpi(req);
227  if (MPI_REQUEST_NULL != request) // Active handle is mandatory
228  {
229  // if (cancel)
230  // {
231  // MPI_Cancel(&request);
232  // }
233  MPI_Request_free(&request);
234  }
235  req = UPstream::Request(MPI_REQUEST_NULL); // Now inactive
236  }
237 }
238 
239 
240 void Foam::UPstream::freeRequests(UList<UPstream::Request>& requests)
241 {
242  // No-op for non-parallel
243  if (!UPstream::parRun())
244  {
245  return;
246  }
247 
248  for (auto& req : requests)
249  {
250  MPI_Request request = PstreamUtils::Cast::to_mpi(req);
251  if (MPI_REQUEST_NULL != request) // Active handle is mandatory
252  {
253  // if (cancel)
254  // {
255  // MPI_Cancel(&request);
256  // }
257  MPI_Request_free(&request);
258  }
259  req = UPstream::Request(MPI_REQUEST_NULL); // Now inactive
260  }
261 }
262 
263 
264 void Foam::UPstream::waitRequests(const label pos, label len)
265 {
266  // No-op for non-parallel, no pending requests or out-of-range
267  if
268  (
270  || (pos < 0 || pos >= PstreamGlobals::outstandingRequests_.size())
271  || !len
272  )
273  {
274  return;
275  }
276 
278  bool trim = true; // Can trim the trailing part of the list
279 
280  // Apply range-checking on slice with (len < 0) behaving like npos
281  // (ie, the rest of the list)
282  if (len >= 0 && len < count)
283  {
284  // A non-trailing slice
285  count = len;
286  trim = false;
287  }
288  // Have count >= 1
289 
291 
292  if (UPstream::debug)
293  {
294  Perr<< "UPstream::waitRequests : starting wait for "
295  << count << " requests starting at " << pos << endl;
296  }
297 
299 
300  if (count == 1)
301  {
302  // On success: sets request to MPI_REQUEST_NULL
303  if (MPI_Wait(waitRequests, MPI_STATUS_IGNORE))
304  {
306  << "MPI_Wait returned with error"
308  }
309  }
310  else if (count > 1)
311  {
312  // On success: sets each request to MPI_REQUEST_NULL
313  if (MPI_Waitall(count, waitRequests, MPI_STATUSES_IGNORE))
314  {
316  << "MPI_Waitall returned with error"
318  }
319  }
320 
322 
323  if (trim)
324  {
325  // Trim the length of outstanding requests
327  }
328 
329  if (UPstream::debug)
330  {
331  Perr<< "UPstream::waitRequests : finished wait." << endl;
332  }
333 }
334 
335 
336 void Foam::UPstream::waitRequests(UList<UPstream::Request>& requests)
337 {
338  // No-op for non-parallel or no pending requests
339  if (!UPstream::parRun() || requests.empty())
340  {
341  return;
342  }
343 
344  // Looks ugly but is legitimate since UPstream::Request is an intptr_t,
345  // which is always large enough to hold an MPI_Request (int or pointer)
346 
347  label count = 0;
348  auto* waitRequests = reinterpret_cast<MPI_Request*>(requests.data());
349 
350  for (auto& req : requests)
351  {
352  MPI_Request request = PstreamUtils::Cast::to_mpi(req);
353 
354  if (MPI_REQUEST_NULL != request) // Apply some prefiltering
355  {
356  waitRequests[count] = request;
357  ++count;
358  }
359  }
360 
361  if (!count)
362  {
363  // No active request handles
364  return;
365  }
366 
368 
369  // On success: sets each request to MPI_REQUEST_NULL
370  if (MPI_Waitall(count, waitRequests, MPI_STATUSES_IGNORE))
371  {
373  << "MPI_Waitall returned with error"
375  }
376 
378 
379  // Everything handled, reset all to MPI_REQUEST_NULL
380  requests = UPstream::Request(MPI_REQUEST_NULL);
381 }
382 
383 
384 bool Foam::UPstream::waitAnyRequest(const label pos, label len)
385 {
386  // No-op for non-parallel, no pending requests or out-of-range
387  if
388  (
390  || (pos < 0 || pos >= PstreamGlobals::outstandingRequests_.size())
391  || !len
392  )
393  {
394  return false;
395  }
396 
398 
399  // Apply range-checking on slice with (len < 0) behaving like npos
400  // (ie, the rest of the list)
401  if (len >= 0 && len < count)
402  {
403  // A non-trailing slice
404  count = len;
405  }
406  // Have count >= 1
407 
409 
410  if (UPstream::debug)
411  {
412  Perr<< "UPstream::waitAnyRequest : starting wait for any of "
413  << count << " requests starting at " << pos << endl;
414  }
415 
417 
418  // On success: sets request to MPI_REQUEST_NULL
419  int index = MPI_UNDEFINED;
420  if (MPI_Waitany(count, waitRequests, &index, MPI_STATUS_IGNORE))
421  {
423  << "MPI_Waitany returned with error"
425  }
426 
428 
429  if (index == MPI_UNDEFINED)
430  {
431  // No active request handles
432  return false;
433  }
434 
435  return true;
436 }
437 
438 
440 (
441  const label pos,
442  label len,
443  DynamicList<int>* indices
444 )
445 {
446  // No-op for non-parallel, no pending requests or out-of-range
447  if
448  (
450  || (pos < 0 || pos >= PstreamGlobals::outstandingRequests_.size())
451  || !len
452  )
453  {
454  if (indices) indices->clear();
455  return false;
456  }
457 
459 
460  // Apply range-checking on slice with (len < 0) behaving like npos
461  // (ie, the rest of the list)
462  if (len >= 0 && len < count)
463  {
464  // A non-trailing slice
465  count = len;
466  }
467  // Have count >= 1
468 
470 
471  if (UPstream::debug)
472  {
473  Perr<< "UPstream:waitSomeRequest : starting wait for some of "
474  << count << " requests starting at " << pos << endl;
475  }
476 
477 
478  // Local temporary storage, or return via calling parameter
479  List<int> tmpIndices;
480  if (indices)
481  {
482  indices->resize_nocopy(count);
483  }
484  else
485  {
486  tmpIndices.resize(count);
487  }
488 
490 
491  // On success: sets non-blocking requests to MPI_REQUEST_NULL
492  int outcount = 0;
493  if
494  (
495  MPI_Waitsome
496  (
497  count,
498  waitRequests,
499  &outcount,
500  (indices ? indices->data() : tmpIndices.data()),
501  MPI_STATUSES_IGNORE
502  )
503  )
504  {
506  << "MPI_Waitsome returned with error"
508  }
509 
511 
512  if (outcount == MPI_UNDEFINED || outcount < 1)
513  {
514  // No active request handles
515  if (indices) indices->clear();
516  return false;
517  }
518 
519  if (indices)
520  {
521  indices->resize(outcount);
522  }
523 
524  return true;
525 }
526 
527 
529 (
530  UList<UPstream::Request>& requests,
531  DynamicList<int>* indices
532 )
533 {
534  // No-op for non-parallel or no pending requests
535  if (!UPstream::parRun() || requests.empty())
536  {
537  if (indices) indices->clear();
538  return false;
539  }
540 
541  // Looks ugly but is legitimate since UPstream::Request is an intptr_t,
542  // which is always large enough to hold an MPI_Request (int or pointer)
543 
544  label count = 0;
545  auto* waitRequests = reinterpret_cast<MPI_Request*>(requests.data());
546 
547  for (auto& req : requests)
548  {
550  ++count;
551  }
552 
553  // Local temporary storage, or return via calling parameter
554  List<int> tmpIndices;
555  if (indices)
556  {
557  indices->resize_nocopy(count);
558  }
559  else
560  {
561  tmpIndices.resize(count);
562  }
563 
564  if (UPstream::debug)
565  {
566  Perr<< "UPstream:waitSomeRequest : starting wait for some of "
567  << requests.size() << " requests" << endl;
568  }
569 
571 
572  // On success: sets non-blocking requests to MPI_REQUEST_NULL
573  int outcount = 0;
574  if
575  (
576  MPI_Waitsome
577  (
578  count,
579  waitRequests,
580  &outcount,
581  (indices ? indices->data() : tmpIndices.data()),
582  MPI_STATUSES_IGNORE
583  )
584  )
585  {
587  << "MPI_Waitsome returned with error"
589  }
590 
592 
593  if (outcount == MPI_UNDEFINED || outcount < 1)
594  {
595  // No active request handles
596  if (indices) indices->clear();
597 
598  // Everything handled or inactive, reset all to MPI_REQUEST_NULL
599  requests = UPstream::Request(MPI_REQUEST_NULL);
600  return false;
601  }
602 
603  if (indices)
604  {
605  indices->resize(outcount);
606  }
607 
608  // Transcribe MPI_Request back into UPstream::Request
609  // - do in reverse order - see note in finishedRequests()
610  {
611  for (label i = requests.size()-1; i >= 0; --i)
612  {
613  requests[i] = UPstream::Request(waitRequests[i]);
614  }
615  }
616 
617  return true;
618 }
619 
620 
621 Foam::label Foam::UPstream::waitAnyRequest(UList<UPstream::Request>& requests)
622 {
623  // No-op for non-parallel or no pending requests
624  if (!UPstream::parRun() || requests.empty())
625  {
626  return -1;
627  }
628 
629  // Looks ugly but is legitimate since UPstream::Request is an intptr_t,
630  // which is always large enough to hold an MPI_Request (int or pointer)
631 
632  label count = 0;
633  auto* waitRequests = reinterpret_cast<MPI_Request*>(requests.data());
634 
635  // Transcribe UPstream::Request into MPI_Request
636  // - do not change locations within the list since these are relevant
637  // for the return index.
638  for (auto& req : requests)
639  {
641  ++count;
642  }
643 
645 
646  // On success: sets request to MPI_REQUEST_NULL
647  int index = MPI_UNDEFINED;
648  if (MPI_Waitany(count, waitRequests, &index, MPI_STATUS_IGNORE))
649  {
651  << "MPI_Waitany returned with error"
653  }
654 
656 
657  if (index == MPI_UNDEFINED)
658  {
659  index = -1; // No outstanding requests
660  }
661 
662  // Transcribe MPI_Request back into UPstream::Request
663  // - do in reverse order - see note in finishedRequests()
664  {
665  for (label i = count-1; i >= 0; --i)
666  {
667  requests[i] = UPstream::Request(waitRequests[i]);
668  }
669 
670  // Trailing portion
671  for (label i = count; i < requests.size(); ++i)
672  {
673  requests[i] = UPstream::Request(MPI_REQUEST_NULL);
674  }
675  }
676 
677  return index;
678 }
679 
680 
681 // FUTURE?
682 //
731 
732 
733 void Foam::UPstream::waitRequest(const label i)
734 {
735  // No-op for non-parallel, or out-of-range (eg, placeholder indices)
736  if
737  (
739  || i < 0
741  )
742  {
743  return;
744  }
745 
746  auto& request = PstreamGlobals::outstandingRequests_[i];
747 
748  // No-op for null request
749  if (MPI_REQUEST_NULL == request)
750  {
751  return;
752  }
753 
754  if (UPstream::debug)
755  {
756  Perr<< "UPstream::waitRequest : starting wait for request:"
757  << i << endl;
758  }
759 
761 
762  // On success: sets request to MPI_REQUEST_NULL
763  if (MPI_Wait(&request, MPI_STATUS_IGNORE))
764  {
766  << "MPI_Wait returned with error"
768  }
769 
771 
772  if (UPstream::debug)
773  {
774  Perr<< "UPstream::waitRequest : finished wait for request:"
775  << i << endl;
776  }
777 }
778 
779 
780 void Foam::UPstream::waitRequest(UPstream::Request& req)
781 {
782  // No-op for non-parallel
783  if (!UPstream::parRun())
784  {
785  return;
786  }
787 
788  MPI_Request request = PstreamUtils::Cast::to_mpi(req);
789 
790  // No-op for null request
791  if (MPI_REQUEST_NULL == request)
792  {
793  return;
794  }
795 
797 
798  if (MPI_Wait(&request, MPI_STATUS_IGNORE))
799  {
801  << "MPI_Wait returned with error"
803  }
804 
806 
807  req = UPstream::Request(MPI_REQUEST_NULL); // Now inactive
808 }
809 
810 
811 bool Foam::UPstream::finishedRequest(const label i)
812 {
813  // No-op for non-parallel, or out-of-range (eg, placeholder indices)
814  if
815  (
817  || i < 0
819  )
820  {
821  return true;
822  }
823 
824  if (UPstream::debug)
825  {
826  Perr<< "UPstream::finishedRequest : check request:"
827  << i << endl;
828  }
829 
830  auto& request = PstreamGlobals::outstandingRequests_[i];
831 
832  // Fast-path (no-op) for null request
833  if (MPI_REQUEST_NULL == request)
834  {
835  return true;
836  }
837 
838  // On success: sets request to MPI_REQUEST_NULL
839  int flag = 0;
840  MPI_Test(&request, &flag, MPI_STATUS_IGNORE);
841 
842  return flag != 0;
843 }
844 
845 
846 bool Foam::UPstream::finishedRequest(UPstream::Request& req)
847 {
848  // No-op for non-parallel
849  if (!UPstream::parRun())
850  {
851  return true;
852  }
853 
854  MPI_Request request = PstreamUtils::Cast::to_mpi(req);
855 
856  // Fast-path (no-op) for null request
857  if (MPI_REQUEST_NULL == request)
858  {
859  return true;
860  }
861 
862  int flag = 0;
863  MPI_Test(&request, &flag, MPI_STATUS_IGNORE);
864 
865  if (flag)
866  {
867  // Success: now inactive
868  req = UPstream::Request(MPI_REQUEST_NULL);
869  }
870 
871  return flag != 0;
872 }
873 
874 
875 bool Foam::UPstream::finishedRequests(const label pos, label len)
876 {
877  // No-op for non-parallel, or out-of-range (eg, placeholder indices)
878  if
879  (
881  || (pos < 0 || pos >= PstreamGlobals::outstandingRequests_.size())
882  || !len
883  )
884  {
885  return true;
886  }
887 
889 
890  // Apply range-checking on slice with (len < 0) behaving like npos
891  // (ie, the rest of the list)
892  if (len >= 0 && len < count)
893  {
894  // A non-trailing slice
895  count = len;
896  }
897  // Have count >= 1
898 
899  if (UPstream::debug)
900  {
901  Perr<< "UPstream::finishedRequests : check " << count
902  << " requests starting at " << pos << endl;
903  }
904 
906 
907  int flag = 1;
908 
909  if (count == 1)
910  {
911  // Fast-path (no-op) for single null request
912  if (MPI_REQUEST_NULL == *waitRequests)
913  {
914  return true;
915  }
916 
917  // On success: sets request to MPI_REQUEST_NULL
918  MPI_Test(waitRequests, &flag, MPI_STATUS_IGNORE);
919  }
920  else if (count > 1)
921  {
922  // On success: sets each request to MPI_REQUEST_NULL
923  // On failure: no request is modified
924  MPI_Testall(count, waitRequests, &flag, MPI_STATUSES_IGNORE);
925  }
926 
927  return flag != 0;
928 }
929 
930 
931 bool Foam::UPstream::finishedRequests(UList<UPstream::Request>& requests)
932 {
933  // No-op for non-parallel or no pending requests
934  if (!UPstream::parRun() || requests.empty())
935  {
936  return true;
937  }
938 
939  // Looks ugly but is legitimate since UPstream::Request is an intptr_t,
940  // which is always large enough to hold an MPI_Request (int or pointer)
941 
942  label count = 0;
943  auto* waitRequests = reinterpret_cast<MPI_Request*>(requests.data());
944 
945  for (auto& req : requests)
946  {
947  MPI_Request request = PstreamUtils::Cast::to_mpi(req);
948 
949  if (MPI_REQUEST_NULL != request) // Apply some prefiltering
950  {
951  waitRequests[count] = request;
952  ++count;
953  }
954  }
955 
956  if (!count)
957  {
958  // No active handles
959  return true;
960  }
961 
962  // On success: sets each request to MPI_REQUEST_NULL
963  // On failure: no request is modified
964  int flag = 0;
965  MPI_Testall(count, waitRequests, &flag, MPI_STATUSES_IGNORE);
966 
967  if (flag)
968  {
969  // Success: reset all requests to MPI_REQUEST_NULL
970  requests = UPstream::Request(MPI_REQUEST_NULL);
971  }
972  else
973  {
974  // Not all done. Recover wrapped representation but in reverse order
975  // since sizeof(MPI_Request) can be smaller than
976  // sizeof(UPstream::Request::value_type)
977  // eg, mpich has MPI_Request as 'int'
978  //
979  // This is uglier that we'd like, but much better than allocating
980  // and freeing a scratch buffer each time we query things.
981 
982  for (label i = count-1; i >= 0; --i)
983  {
984  requests[i] = UPstream::Request(waitRequests[i]);
985  }
986 
987  // Trailing portion
988  for (label i = count; i < requests.size(); ++i)
989  {
990  requests[i] = UPstream::Request(MPI_REQUEST_NULL);
991  }
992  }
993 
994  return flag != 0;
995 }
996 
997 
998 bool Foam::UPstream::finishedRequestPair(label& req0, label& req1)
999 {
1000  // No-op for non-parallel
1001  if (!UPstream::parRun())
1002  {
1003  req0 = -1;
1004  req1 = -1;
1005  return true;
1006  }
1007 
1008  bool anyActive = false;
1009  MPI_Request waitRequests[2];
1010 
1011  // No-op for out-of-range (eg, placeholder indices)
1012 
1013  if (req0 >= 0 && req0 < PstreamGlobals::outstandingRequests_.size())
1014  {
1016  }
1017  else
1018  {
1019  waitRequests[0] = MPI_REQUEST_NULL;
1020  }
1021 
1022  if (req1 >= 0 && req1 < PstreamGlobals::outstandingRequests_.size())
1023  {
1025  }
1026  else
1027  {
1028  waitRequests[1] = MPI_REQUEST_NULL;
1029  }
1030 
1031  if (MPI_REQUEST_NULL != waitRequests[0]) // An active handle
1032  {
1033  anyActive = true;
1034  }
1035  else
1036  {
1037  req0 = -1;
1038  }
1039 
1040  if (MPI_REQUEST_NULL != waitRequests[1]) // An active handle
1041  {
1042  anyActive = true;
1043  }
1044  else
1045  {
1046  req1 = -1;
1047  }
1048 
1049  if (!anyActive)
1050  {
1051  // No active handles
1052  return true;
1053  }
1054 
1056 
1057  // On success: sets each request to MPI_REQUEST_NULL
1058  int indices[2];
1059  int outcount = 0;
1060  if
1061  (
1062  MPI_Testsome
1063  (
1064  2,
1065  waitRequests,
1066  &outcount,
1067  indices,
1068  MPI_STATUSES_IGNORE
1069  )
1070  )
1071  {
1073  << "MPI_Testsome returned with error"
1074  << Foam::abort(FatalError);
1075  }
1076 
1078 
1079  if (outcount == MPI_UNDEFINED)
1080  {
1081  // No active request handles.
1082  // Slight pedantic, but copy back requests in case they were altered
1083 
1084  if (req0 >= 0)
1085  {
1087  }
1088 
1089  if (req1 >= 0)
1090  {
1092  }
1093 
1094  // Flag indices as 'done'
1095  req0 = -1;
1096  req1 = -1;
1097  return true;
1098  }
1099 
1100  // Copy back requests to their 'stack' locations
1101  for (int i = 0; i < outcount; ++i)
1102  {
1103  const int idx = indices[i];
1104 
1105  if (idx == 0)
1106  {
1107  if (req0 >= 0)
1108  {
1110  req0 = -1;
1111  }
1112  }
1113  if (idx == 1)
1114  {
1115  if (req1 >= 0)
1116  {
1118  req1 = -1;
1119  }
1120  }
1121  }
1122 
1123  return (outcount > 0);
1124 }
1125 
1126 
1127 void Foam::UPstream::waitRequestPair(label& req0, label& req1)
1128 {
1129  // No-op for non-parallel. Flag indices as 'done'
1130  if (!UPstream::parRun())
1131  {
1132  req0 = -1;
1133  req1 = -1;
1134  return;
1135  }
1136 
1137  int count = 0;
1138  MPI_Request waitRequests[2];
1139 
1140  // No-op for out-of-range (eg, placeholder indices)
1141  // Prefilter inactive handles
1142 
1143  if (req0 >= 0 && req0 < PstreamGlobals::outstandingRequests_.size())
1144  {
1146  PstreamGlobals::outstandingRequests_[req0] = MPI_REQUEST_NULL;
1147 
1148  if (MPI_REQUEST_NULL != waitRequests[count]) // An active handle
1149  {
1150  ++count;
1151  }
1152  }
1153 
1154  if (req1 >= 0 && req1 < PstreamGlobals::outstandingRequests_.size())
1155  {
1157  PstreamGlobals::outstandingRequests_[req1] = MPI_REQUEST_NULL;
1158 
1159  if (MPI_REQUEST_NULL != waitRequests[count]) // An active handle
1160  {
1161  ++count;
1162  }
1163  }
1164 
1165  // Flag in advance as being handled
1166  req0 = -1;
1167  req1 = -1;
1168 
1169  if (!count)
1170  {
1171  // No active handles
1172  return;
1173  }
1174 
1176 
1177  // On success: sets each request to MPI_REQUEST_NULL
1178  if (MPI_Waitall(count, waitRequests, MPI_STATUSES_IGNORE))
1179  {
1181  << "MPI_Waitall returned with error"
1182  << Foam::abort(FatalError);
1183  }
1184 
1186 }
1187 
1188 
1189 // ************************************************************************* //
prefixOSstream Perr
OSstream wrapped stderr (std::cerr) with parallel prefix.
DynamicList< MPI_Request > outstandingRequests_
Outstanding non-blocking operations.
static void removeRequests(const label pos, label len=-1)
Non-blocking comms: cancel/free outstanding requests (from position onwards) and remove from internal...
void reset() noexcept
Reset to default constructed value (MPI_REQUEST_NULL)
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:608
Functions to wrap MPI_Bcast, MPI_Allreduce, MPI_Iallreduce etc.
static label nRequests() noexcept
Number of outstanding requests (on the internal list of requests)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1061
static void cancelRequest(const label i)
Non-blocking comms: cancel and free outstanding request. Corresponds to MPI_Cancel() + MPI_Request_fr...
static bool finishedRequest(const label i)
Non-blocking comms: has request i finished? Corresponds to MPI_Test()
static void freeRequest(UPstream::Request &req)
Non-blocking comms: free outstanding request. Corresponds to MPI_Request_free()
static void freeRequests(UList< UPstream::Request > &requests)
Non-blocking comms: free outstanding requests. Corresponds to MPI_Request_free()
static void addWaitTime()
Add time increment to wait time.
bool good() const noexcept
True if not equal to MPI_REQUEST_NULL.
static void waitRequests()
Wait for all requests to finish.
Definition: UPstream.H:1561
scalar range
static bool finishedRequestPair(label &req0, label &req1)
Non-blocking comms: have both requests finished? Corresponds to pair of MPI_Test() ...
dimensionedScalar pos(const dimensionedScalar &ds)
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of &#39;true&#39; entries.
Definition: BitOps.H:73
string trim(const std::string &s)
Return string trimmed of leading and trailing whitespace.
Definition: stringOps.C:1033
errorManip< error > abort(error &err)
Definition: errorManip.H:139
static bool waitAnyRequest(const label pos, label len=-1)
Wait until any request (from position onwards) has finished. Corresponds to MPI_Waitany() ...
const direction noexcept
Definition: Scalar.H:258
static void beginTiming()
Update timer prior to measurement.
static void resetRequests(const label n)
Truncate outstanding requests to given length, which is expected to be in the range [0 to nRequests()...
int debug
Static debugging option.
static void waitRequestPair(label &req0, label &req1)
Non-blocking comms: wait for both requests to finish. Corresponds to pair of MPI_Wait() ...
static void addRequest(UPstream::Request &req)
Transfer the (wrapped) MPI request to the internal global list.
Request() noexcept
Default construct as MPI_REQUEST_NULL.
static void cancelRequests(UList< UPstream::Request > &requests)
Non-blocking comms: cancel and free outstanding requests. Corresponds to MPI_Cancel() + MPI_Request_f...
label n
static std::enable_if< std::is_pointer< Type >::value, Type >::type to_mpi(const UPstream::Communicator &arg) noexcept
Definition: openfoam_mpi.H:53
static void waitRequest(const label i)
Wait until request i has finished. Corresponds to MPI_Wait()
static bool waitSomeRequests(const label pos, label len=-1, DynamicList< int > *indices=nullptr)
Wait until some requests (from position onwards) have finished. Corresponds to MPI_Waitsome() ...
static bool finishedRequests(const label pos, label len=-1)
Non-blocking comms: have all requests (from position onwards) finished? Corresponds to MPI_Testall() ...