Reference documentation for deal.II version 9.3.3
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
work_stream.h
Go to the documentation of this file.
1// ---------------------------------------------------------------------
2//
3// Copyright (C) 2008 - 2020 by the deal.II authors
4//
5// This file is part of the deal.II library.
6//
7// The deal.II library is free software; you can use it, redistribute
8// it, and/or modify it under the terms of the GNU Lesser General
9// Public License as published by the Free Software Foundation; either
10// version 2.1 of the License, or (at your option) any later version.
11// The full text of the license can be found in the file LICENSE.md at
12// the top level directory of deal.II.
13//
14// ---------------------------------------------------------------------
15
16#ifndef dealii_work_stream_h
17# define dealii_work_stream_h
18
19
20# include <deal.II/base/config.h>
21
29
30# ifdef DEAL_II_WITH_TBB
31# ifdef DEAL_II_TBB_WITH_ONEAPI
32# include <tbb/parallel_pipeline.h>
33# else
34# include <tbb/pipeline.h>
35# endif
36# endif
37
38# include <functional>
39# include <iterator>
40# include <memory>
41# include <utility>
42# include <vector>
43
45
46
47
160namespace WorkStream
161{
166 namespace internal
167 {
168# ifdef DEAL_II_WITH_TBB
183 namespace tbb_no_coloring
184 {
188 template <typename Iterator, typename ScratchData, typename CopyData>
190 {
191 public:
198 struct ItemType
199 {
206 {
207 std::unique_ptr<ScratchData> scratch_data;
209
214 : currently_in_use(false)
215 {}
216
217 ScratchDataObject(ScratchData *p, const bool in_use)
218 : scratch_data(p)
219 , currently_in_use(in_use)
220 {}
221
222 // Provide a copy constructor that actually doesn't copy the
223 // internal state. This makes handling ScratchAndCopyDataObjects
224 // easier to handle with STL containers.
226 : currently_in_use(false)
227 {}
228
229 ScratchDataObject(ScratchDataObject &&o) noexcept = default;
230 };
231
232
237 using ScratchDataList = std::list<ScratchDataObject>;
238
243 std::vector<Iterator> iterators;
244
250 std::vector<CopyData> copy_datas;
251
257 unsigned int n_iterators;
258
291
296 const ScratchData *sample_scratch_data;
297
303
304
310 : n_iterators(0)
311 , scratch_data(nullptr)
312 , sample_scratch_data(nullptr)
313 , currently_in_use(false)
314 {}
315 };
316
317
324 const Iterator & end,
325 const unsigned int buffer_size,
326 const unsigned int chunk_size,
327 const ScratchData &sample_scratch_data,
328 const CopyData & sample_copy_data)
330 , item_buffer(buffer_size)
333 {
334 // initialize the elements of the ring buffer
335 for (auto &item : item_buffer)
336 {
337 Assert(item.n_iterators == 0, ExcInternalError());
338
339 item.iterators.resize(chunk_size,
341 item.scratch_data = &thread_local_scratch;
342 item.sample_scratch_data = &sample_scratch_data;
343 item.copy_datas.resize(chunk_size, sample_copy_data);
344 item.currently_in_use = false;
345 }
346 }
347
348
352 ItemType *
354 {
355 // find first unused item. we know that there must be one
356 // because we have set the maximal number of tokens in flight
357 // and have set the ring buffer to have exactly this size. so
358 // if this function is called, we know that less than the
359 // maximal number of items in currently in flight
360 //
361 // note that we need not lock access to this array since
362 // the current stage is run sequentially and we can therefore
363 // enter the following block only once at any given time.
364 // thus, there can be no race condition between checking that
365 // a flag is false and setting it to true. (there may be
366 // another thread where we release items and set 'false'
367 // flags to 'true', but that too does not produce any
368 // problems)
369 ItemType *current_item = nullptr;
370 for (unsigned int i = 0; i < item_buffer.size(); ++i)
371 if (item_buffer[i].currently_in_use == false)
372 {
373 item_buffer[i].currently_in_use = true;
374 current_item = &item_buffer[i];
375 break;
376 }
377 Assert(current_item != nullptr,
378 ExcMessage("This can't be. There must be a free item!"));
379
380 // initialize the next item. it may
381 // consist of at most chunk_size
382 // elements
383 current_item->n_iterators = 0;
384 while ((remaining_iterator_range.first !=
385 remaining_iterator_range.second) &&
386 (current_item->n_iterators < chunk_size))
387 {
388 current_item->iterators[current_item->n_iterators] =
390
392 ++current_item->n_iterators;
393 }
394
395 if (current_item->n_iterators == 0)
396 // there were no items
397 // left. terminate the pipeline
398 return nullptr;
399 else
400 return current_item;
401 }
402
403 private:
408 std::pair<Iterator, Iterator> remaining_iterator_range;
409
413 std::vector<ItemType> item_buffer;
414
447
453 const ScratchData &sample_scratch_data;
454
461 const unsigned int chunk_size;
462 };
463
464
465
466 template <typename Worker,
467 typename Copier,
468 typename Iterator,
469 typename ScratchData,
470 typename CopyData>
471 void
472 run(const Iterator & begin,
473 const typename identity<Iterator>::type &end,
474 Worker worker,
475 Copier copier,
476 const ScratchData & sample_scratch_data,
477 const CopyData & sample_copy_data,
478 const unsigned int queue_length,
479 const unsigned int chunk_size)
480 {
481 using ItemType = typename IteratorRangeToItemStream<Iterator,
482 ScratchData,
483 CopyData>::ItemType;
484
485 // create the three stages of the pipeline
487 iterator_range_to_item_stream(begin,
488 end,
489 queue_length,
491 sample_scratch_data,
492 sample_copy_data);
493 auto tbb_item_stream_filter = tbb::make_filter<void, ItemType *>(
495 tbb::filter_mode::serial_in_order,
496# else
497 tbb::filter::serial,
498# endif
499 [&](tbb::flow_control &fc) -> ItemType * {
500 if (const auto item = iterator_range_to_item_stream.get_item())
501 return item;
502 else
503 {
504 fc.stop();
505 return nullptr;
506 }
507 });
508
509 auto tbb_worker_filter = tbb::make_filter<ItemType *, ItemType *>(
511 tbb::filter_mode::parallel,
512# else
513 tbb::filter::parallel,
514# endif
515 [worker =
516 std::function<void(const Iterator &, ScratchData &, CopyData &)>(
517 worker),
518 copier_exist =
519 static_cast<bool>(std::function<void(const CopyData &)>(copier))](
520 ItemType *current_item) {
521 // we need to find an unused scratch data object in the list that
522 // corresponds to the current thread and then mark it as used. if
523 // we can't find one, create one
524 //
525 // as discussed in the discussion of the documentation of the
526 // IteratorRangeToItemStream::scratch_data variable, there is no
527 // need to synchronize access to this variable using a mutex
528 // as long as we have no yield-point in between. this means that
529 // we can't take an iterator into the list now and expect it to
530 // still be valid after calling the worker, but we at least do
531 // not have to lock the following section
532 ScratchData *scratch_data = nullptr;
533 {
534 // see if there is an unused object. if so, grab it and mark
535 // it as used
536 for (auto &p : current_item->scratch_data->get())
537 if (p.currently_in_use == false)
538 {
539 scratch_data = p.scratch_data.get();
540 p.currently_in_use = true;
541
542 break;
543 }
544
545 // if no object was found, create one and mark it as used
546 if (scratch_data == nullptr)
547 {
548 scratch_data =
549 new ScratchData(*current_item->sample_scratch_data);
550 current_item->scratch_data->get().emplace_back(scratch_data,
551 true);
552 }
553 }
554
555 // then call the worker function on each element of the chunk we
556 // were given. since these worker functions are called on separate
557 // threads, nothing good can happen if they throw an exception and
558 // we are best off catching it and showing an error message
559 for (unsigned int i = 0; i < current_item->n_iterators; ++i)
560 {
561 try
562 {
563 if (worker)
564 worker(current_item->iterators[i],
565 *scratch_data,
566 current_item->copy_datas[i]);
567 }
568 catch (const std::exception &exc)
569 {
571 }
572 catch (...)
573 {
575 }
576 }
577
578 // finally mark the scratch object as unused again. as above, there
579 // is no need to lock anything here since the object we work on
580 // is thread-local
581 for (auto &p : current_item->scratch_data->get())
582 if (p.scratch_data.get() == scratch_data)
583 {
584 Assert(p.currently_in_use == true, ExcInternalError());
585 p.currently_in_use = false;
586
587 break;
588 }
589
590 // if there is no copier, mark current item as usable again
591 if (copier_exist == false)
592 current_item->currently_in_use = false;
593
594
595 // Then return the original pointer
596 // to the now modified object. The copier will work on it next.
597 return current_item;
598 });
599
600 auto tbb_copier_filter = tbb::make_filter<ItemType *, void>(
602 tbb::filter_mode::serial_in_order,
603# else
604 tbb::filter::serial,
605# endif
606 [copier = std::function<void(const CopyData &)>(copier)](
607 ItemType *current_item) {
608 if (copier)
609 {
610 // Initiate copying data. For the same reasons as in the worker
611 // class above, catch exceptions rather than letting them
612 // propagate into unknown territories:
613 for (unsigned int i = 0; i < current_item->n_iterators; ++i)
614 {
615 try
616 {
617 copier(current_item->copy_datas[i]);
618 }
619 catch (const std::exception &exc)
620 {
622 }
623 catch (...)
624 {
626 }
627 }
628 }
629 // mark current item as usable again
630 current_item->currently_in_use = false;
631 });
632
633 // Now create a pipeline from these stages and execute it:
634 tbb::parallel_pipeline(queue_length,
635 tbb_item_stream_filter & tbb_worker_filter &
636 tbb_copier_filter);
637 }
638
639 } // namespace tbb_no_coloring
640# endif // DEAL_II_WITH_TBB
641
642
649 namespace sequential
650 {
654 template <typename Worker,
655 typename Copier,
656 typename Iterator,
657 typename ScratchData,
658 typename CopyData>
659 void
660 run(const Iterator & begin,
661 const typename identity<Iterator>::type &end,
662 Worker worker,
663 Copier copier,
664 const ScratchData & sample_scratch_data,
665 const CopyData & sample_copy_data)
666 {
667 // need to copy the sample since it is marked const
668 ScratchData scratch_data = sample_scratch_data;
669 CopyData copy_data = sample_copy_data; // NOLINT
670
671 // Optimization: Check if the functions are not the zero function. To
672 // check zero-ness, create a C++ function out of it:
673 const bool have_worker =
674 (static_cast<const std::function<
675 void(const Iterator &, ScratchData &, CopyData &)> &>(worker)) !=
676 nullptr;
677 const bool have_copier =
678 (static_cast<const std::function<void(const CopyData &)> &>(
679 copier)) != nullptr;
680
681 // Finally loop over all items and perform the necessary work:
682 for (Iterator i = begin; i != end; ++i)
683 {
684 if (have_worker)
685 worker(i, scratch_data, copy_data);
686 if (have_copier)
687 copier(copy_data);
688 }
689 }
690
691
692
696 template <typename Worker,
697 typename Copier,
698 typename Iterator,
699 typename ScratchData,
700 typename CopyData>
701 void
702 run(const std::vector<std::vector<Iterator>> &colored_iterators,
703 Worker worker,
704 Copier copier,
705 const ScratchData & sample_scratch_data,
706 const CopyData & sample_copy_data)
707 {
708 // need to copy the sample since it is marked const
709 ScratchData scratch_data = sample_scratch_data;
710 CopyData copy_data = sample_copy_data; // NOLINT
711
712 // Optimization: Check if the functions are not the zero function. To
713 // check zero-ness, create a C++ function out of it:
714 const bool have_worker =
715 (static_cast<const std::function<
716 void(const Iterator &, ScratchData &, CopyData &)> &>(worker)) !=
717 nullptr;
718 const bool have_copier =
719 (static_cast<const std::function<void(const CopyData &)> &>(
720 copier)) != nullptr;
721
722 // Finally loop over all items and perform the necessary work:
723 for (unsigned int color = 0; color < colored_iterators.size(); ++color)
724 if (colored_iterators[color].size() > 0)
725 for (auto &it : colored_iterators[color])
726 {
727 if (have_worker)
728 worker(it, scratch_data, copy_data);
729 if (have_copier)
730 copier(copy_data);
731 }
732 }
733
734 } // namespace sequential
735
736
737
738# ifdef DEAL_II_WITH_TBB
746 namespace tbb_colored
747 {
753 template <typename Iterator, typename ScratchData, typename CopyData>
755 {
756 std::unique_ptr<ScratchData> scratch_data;
757 std::unique_ptr<CopyData> copy_data;
759
764 : currently_in_use(false)
765 {}
766
767 ScratchAndCopyDataObjects(std::unique_ptr<ScratchData> &&p,
768 std::unique_ptr<CopyData> && q,
769 const bool in_use)
770 : scratch_data(std::move(p))
771 , copy_data(std::move(q))
772 , currently_in_use(in_use)
773 {}
774
775 // Provide a copy constructor that actually doesn't copy the
776 // internal state. This makes handling ScratchAndCopyDataObjects
777 // easier to handle with STL containers.
779 : currently_in_use(false)
780 {}
781 };
782
783
784
790 template <typename Iterator, typename ScratchData, typename CopyData>
792 {
793 public:
798 const std::function<void(const Iterator &, ScratchData &, CopyData &)>
799 & worker,
800 const std::function<void(const CopyData &)> &copier,
801 const ScratchData & sample_scratch_data,
802 const CopyData & sample_copy_data)
803 : worker(worker)
804 , copier(copier)
807 {}
808
809
814 void
815 operator()(const tbb::blocked_range<
816 typename std::vector<Iterator>::const_iterator> &range)
817 {
818 // we need to find an unused scratch and corresponding copy
819 // data object in the list that corresponds to the current
820 // thread and then mark it as used. If we can't find one,
821 // create one as discussed in the discussion of the documentation
822 // of the IteratorRangeToItemStream::scratch_data variable,
823 // there is no need to synchronize access to this variable
824 // using a mutex as long as we have no yield-point in between.
825 // This means that we can't take an iterator into the list
826 // now and expect it to still be valid after calling the worker,
827 // but we at least do not have to lock the following section.
828 ScratchData *scratch_data = nullptr;
829 CopyData * copy_data = nullptr;
830 {
831 ScratchAndCopyDataList &scratch_and_copy_data_list = data.get();
832
833 // see if there is an unused object. if so, grab it and mark
834 // it as used
835 for (typename ScratchAndCopyDataList::iterator p =
836 scratch_and_copy_data_list.begin();
837 p != scratch_and_copy_data_list.end();
838 ++p)
839 if (p->currently_in_use == false)
840 {
841 scratch_data = p->scratch_data.get();
842 copy_data = p->copy_data.get();
843 p->currently_in_use = true;
844 break;
845 }
846
847 // if no element in the list was found, create one and mark it as
848 // used
849 if (scratch_data == nullptr)
850 {
851 Assert(copy_data == nullptr, ExcInternalError());
852
853 scratch_and_copy_data_list.emplace_back(
854 std::make_unique<ScratchData>(sample_scratch_data),
855 std::make_unique<CopyData>(sample_copy_data),
856 true);
857 scratch_data =
858 scratch_and_copy_data_list.back().scratch_data.get();
859 copy_data = scratch_and_copy_data_list.back().copy_data.get();
860 }
861 }
862
863 // then call the worker and copier functions on each
864 // element of the chunk we were given.
865 for (typename std::vector<Iterator>::const_iterator p = range.begin();
866 p != range.end();
867 ++p)
868 {
869 try
870 {
871 if (worker)
872 worker(*p, *scratch_data, *copy_data);
873 if (copier)
874 copier(*copy_data);
875 }
876 catch (const std::exception &exc)
877 {
879 }
880 catch (...)
881 {
883 }
884 }
885
886 // finally mark the scratch object as unused again. as above, there
887 // is no need to lock anything here since the object we work on
888 // is thread-local
889 {
890 ScratchAndCopyDataList &scratch_and_copy_data_list = data.get();
891
892 for (typename ScratchAndCopyDataList::iterator p =
893 scratch_and_copy_data_list.begin();
894 p != scratch_and_copy_data_list.end();
895 ++p)
896 if (p->scratch_data.get() == scratch_data)
897 {
898 Assert(p->currently_in_use == true, ExcInternalError());
899 p->currently_in_use = false;
900 }
901 }
902 }
903
904 private:
905 using ScratchAndCopyDataObjects = typename tbb_colored::
906 ScratchAndCopyDataObjects<Iterator, ScratchData, CopyData>;
907
912 using ScratchAndCopyDataList = std::list<ScratchAndCopyDataObjects>;
913
915
920 const std::function<void(const Iterator &, ScratchData &, CopyData &)>
922
927 const std::function<void(const CopyData &)> copier;
928
932 const ScratchData &sample_scratch_data;
933 const CopyData & sample_copy_data;
934 };
935
939 template <typename Worker,
940 typename Copier,
941 typename Iterator,
942 typename ScratchData,
943 typename CopyData>
944 void
945 run(const std::vector<std::vector<Iterator>> &colored_iterators,
946 Worker worker,
947 Copier copier,
948 const ScratchData & sample_scratch_data,
949 const CopyData & sample_copy_data,
950 const unsigned int chunk_size)
951 {
952 // loop over the various colors of what we're given
953 for (unsigned int color = 0; color < colored_iterators.size(); ++color)
954 if (colored_iterators[color].size() > 0)
955 {
956 using WorkerAndCopier = internal::tbb_colored::
957 WorkerAndCopier<Iterator, ScratchData, CopyData>;
958
959 using RangeType = typename std::vector<Iterator>::const_iterator;
960
961 WorkerAndCopier worker_and_copier(worker,
962 copier,
963 sample_scratch_data,
964 sample_copy_data);
965
967 colored_iterators[color].begin(),
968 colored_iterators[color].end(),
969 [&worker_and_copier](
970 const tbb::blocked_range<
971 typename std::vector<Iterator>::const_iterator> &range) {
972 worker_and_copier(range);
973 },
974 chunk_size);
975 }
976 }
977
978 } // namespace tbb_colored
979# endif // DEAL_II_WITH_TBB
980
981
982 } // namespace internal
983
984
985
1033 template <typename Worker,
1034 typename Copier,
1035 typename Iterator,
1036 typename ScratchData,
1037 typename CopyData>
1038 void
1039 run(const std::vector<std::vector<Iterator>> &colored_iterators,
1040 Worker worker,
1041 Copier copier,
1042 const ScratchData & sample_scratch_data,
1043 const CopyData & sample_copy_data,
1044 const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
1045 const unsigned int chunk_size = 8);
1046
1047
1097 template <typename Worker,
1098 typename Copier,
1099 typename Iterator,
1100 typename ScratchData,
1101 typename CopyData>
1102 void
1103 run(const Iterator & begin,
1104 const typename identity<Iterator>::type &end,
1105 Worker worker,
1106 Copier copier,
1107 const ScratchData & sample_scratch_data,
1108 const CopyData & sample_copy_data,
1109 const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
1110 const unsigned int chunk_size = 8)
1111 {
1112 Assert(queue_length > 0,
1113 ExcMessage("The queue length must be at least one, and preferably "
1114 "larger than the number of processors on this system."));
1115 (void)queue_length; // removes -Wunused-parameter warning in optimized mode
1116 Assert(chunk_size > 0, ExcMessage("The chunk_size must be at least one."));
1117 (void)chunk_size; // removes -Wunused-parameter warning in optimized mode
1118
1119 // If no work then skip. (only use operator!= for iterators since we may
1120 // not have an equality comparison operator)
1121 if (!(begin != end))
1122 return;
1123
1125 {
1126# ifdef DEAL_II_WITH_TBB
1127 if (static_cast<const std::function<void(const CopyData &)> &>(copier))
1128 {
1129 // If we have a copier, run the algorithm:
1131 end,
1132 worker,
1133 copier,
1134 sample_scratch_data,
1135 sample_copy_data,
1136 queue_length,
1137 chunk_size);
1138 }
1139 else
1140 {
1141 // There is no copier function. in this case, we have an
1142 // embarrassingly parallel problem where we can
1143 // essentially apply parallel_for. because parallel_for
1144 // requires subdividing the range for which operator- is
1145 // necessary between iterators, it is often inefficient to
1146 // apply it directly to cell ranges and similar iterator
1147 // types for which operator- is expensive or, in fact,
1148 // nonexistent. rather, in that case, we simply copy the
1149 // iterators into a large array and use operator- on
1150 // iterators to this array of iterators.
1151 //
1152 // instead of duplicating code, this is essentially the
1153 // same situation we have in the colored implementation below, so we
1154 // just defer to that place
1155 std::vector<std::vector<Iterator>> all_iterators(1);
1156 for (Iterator p = begin; p != end; ++p)
1157 all_iterators[0].push_back(p);
1158
1159 run(all_iterators,
1160 worker,
1161 copier,
1162 sample_scratch_data,
1163 sample_copy_data,
1164 queue_length,
1165 chunk_size);
1166 }
1167
1168 // exit this function to not run the sequential version below:
1169 return;
1170# endif
1171 }
1172
1173 // no TBB installed or we are requested to run sequentially:
1175 begin, end, worker, copier, sample_scratch_data, sample_copy_data);
1176 }
1177
1178
1179
1187 template <typename Worker,
1188 typename Copier,
1189 typename IteratorRangeType,
1190 typename ScratchData,
1191 typename CopyData,
1192 typename = typename std::enable_if<
1194 void
1195 run(IteratorRangeType iterator_range,
1196 Worker worker,
1197 Copier copier,
1198 const ScratchData &sample_scratch_data,
1199 const CopyData & sample_copy_data,
1200 const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
1201 const unsigned int chunk_size = 8)
1202 {
1203 // Call the function above
1204 run(iterator_range.begin(),
1205 iterator_range.end(),
1206 worker,
1207 copier,
1208 sample_scratch_data,
1209 sample_copy_data,
1210 queue_length,
1211 chunk_size);
1212 }
1213
1214
1215
1219 template <typename Worker,
1220 typename Copier,
1221 typename Iterator,
1222 typename ScratchData,
1223 typename CopyData>
1224 void
1225 run(const IteratorRange<Iterator> &iterator_range,
1226 Worker worker,
1227 Copier copier,
1228 const ScratchData & sample_scratch_data,
1229 const CopyData & sample_copy_data,
1230 const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
1231 const unsigned int chunk_size = 8)
1232 {
1233 // Call the function above
1234 run(iterator_range.begin(),
1235 iterator_range.end(),
1236 worker,
1237 copier,
1238 sample_scratch_data,
1239 sample_copy_data,
1240 queue_length,
1241 chunk_size);
1242 }
1243
1244
1245
1246 template <typename Worker,
1247 typename Copier,
1248 typename Iterator,
1249 typename ScratchData,
1250 typename CopyData>
1251 void
1252 run(const std::vector<std::vector<Iterator>> &colored_iterators,
1253 Worker worker,
1254 Copier copier,
1255 const ScratchData & sample_scratch_data,
1256 const CopyData & sample_copy_data,
1257 const unsigned int queue_length,
1258 const unsigned int chunk_size)
1259 {
1260 Assert(queue_length > 0,
1261 ExcMessage("The queue length must be at least one, and preferably "
1262 "larger than the number of processors on this system."));
1263 (void)queue_length; // removes -Wunused-parameter warning in optimized mode
1264 Assert(chunk_size > 0, ExcMessage("The chunk_size must be at least one."));
1265 (void)chunk_size; // removes -Wunused-parameter warning in optimized mode
1266
1267
1269 {
1270# ifdef DEAL_II_WITH_TBB
1271 internal::tbb_colored::run(colored_iterators,
1272 worker,
1273 copier,
1274 sample_scratch_data,
1275 sample_copy_data,
1276 chunk_size);
1277
1278 // exit this function to not run the sequential version below:
1279 return;
1280# endif
1281 }
1282
1283 // run all colors sequentially:
1284 {
1285 internal::sequential::run(colored_iterators,
1286 worker,
1287 copier,
1288 sample_scratch_data,
1289 sample_copy_data);
1290 }
1291 }
1292
1293
1294
1336 template <typename MainClass,
1337 typename Iterator,
1338 typename ScratchData,
1339 typename CopyData>
1340 void
1341 run(const Iterator & begin,
1342 const typename identity<Iterator>::type &end,
1343 MainClass & main_object,
1344 void (MainClass::*worker)(const Iterator &, ScratchData &, CopyData &),
1345 void (MainClass::*copier)(const CopyData &),
1346 const ScratchData &sample_scratch_data,
1347 const CopyData & sample_copy_data,
1348 const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
1349 const unsigned int chunk_size = 8)
1350 {
1351 // forward to the other function
1352 run(begin,
1353 end,
1354 [&main_object, worker](const Iterator &iterator,
1355 ScratchData & scratch_data,
1356 CopyData & copy_data) {
1357 (main_object.*worker)(iterator, scratch_data, copy_data);
1358 },
1359 [&main_object, copier](const CopyData &copy_data) {
1360 (main_object.*copier)(copy_data);
1361 },
1362 sample_scratch_data,
1363 sample_copy_data,
1364 queue_length,
1365 chunk_size);
1366 }
1367
1368
1369 template <typename MainClass,
1370 typename Iterator,
1371 typename ScratchData,
1372 typename CopyData>
1373 void
1376 MainClass &main_object,
1377 void (MainClass::*worker)(const Iterator &, ScratchData &, CopyData &),
1378 void (MainClass::*copier)(const CopyData &),
1379 const ScratchData &sample_scratch_data,
1380 const CopyData & sample_copy_data,
1381 const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
1382 const unsigned int chunk_size = 8)
1383 {
1384 // forward to the other function
1385 run(begin,
1386 end,
1387 [&main_object, worker](const Iterator &iterator,
1388 ScratchData & scratch_data,
1389 CopyData & copy_data) {
1390 (main_object.*worker)(iterator, scratch_data, copy_data);
1391 },
1392 [&main_object, copier](const CopyData &copy_data) {
1393 (main_object.*copier)(copy_data);
1394 },
1395 sample_scratch_data,
1396 sample_copy_data,
1397 queue_length,
1398 chunk_size);
1399 }
1400
1401
1402
1410 template <typename MainClass,
1411 typename IteratorRangeType,
1412 typename ScratchData,
1413 typename CopyData,
1414 typename = typename std::enable_if<
1416 void
1417 run(IteratorRangeType iterator_range,
1418 MainClass & main_object,
1419 void (MainClass::*worker)(
1421 ScratchData &,
1422 CopyData &),
1423 void (MainClass::*copier)(const CopyData &),
1424 const ScratchData &sample_scratch_data,
1425 const CopyData & sample_copy_data,
1426 const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
1427 const unsigned int chunk_size = 8)
1428 {
1429 // Call the function above
1430 run(std::begin(iterator_range),
1431 std::end(iterator_range),
1432 main_object,
1433 worker,
1434 copier,
1435 sample_scratch_data,
1436 sample_copy_data,
1437 queue_length,
1438 chunk_size);
1439 }
1440
1441
1442
1446 template <typename MainClass,
1447 typename Iterator,
1448 typename ScratchData,
1449 typename CopyData>
1450 void
1452 MainClass & main_object,
1453 void (MainClass::*worker)(const Iterator &, ScratchData &, CopyData &),
1454 void (MainClass::*copier)(const CopyData &),
1455 const ScratchData &sample_scratch_data,
1456 const CopyData & sample_copy_data,
1457 const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
1458 const unsigned int chunk_size = 8)
1459 {
1460 // Call the function above
1461 run(std::begin(iterator_range),
1462 std::end(iterator_range),
1463 main_object,
1464 worker,
1465 copier,
1466 sample_scratch_data,
1467 sample_copy_data,
1468 queue_length,
1469 chunk_size);
1470 }
1471
1472} // namespace WorkStream
1473
1474
1475
1477
1478
1479
1480//---------------------------- work_stream.h ---------------------------
1481// end of #ifndef dealii_work_stream_h
1482#endif
1483//---------------------------- work_stream.h ---------------------------
IteratorOverIterators end() const
IteratorOverIterators begin()
static unsigned int n_threads()
std::list< ScratchAndCopyDataObjects > ScratchAndCopyDataList
Definition: work_stream.h:912
WorkerAndCopier(const std::function< void(const Iterator &, ScratchData &, CopyData &)> &worker, const std::function< void(const CopyData &)> &copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data)
Definition: work_stream.h:797
Threads::ThreadLocalStorage< ScratchAndCopyDataList > data
Definition: work_stream.h:914
void operator()(const tbb::blocked_range< typename std::vector< Iterator >::const_iterator > &range)
Definition: work_stream.h:815
const std::function< void(const Iterator &, ScratchData &, CopyData &)> worker
Definition: work_stream.h:921
typename tbb_colored::ScratchAndCopyDataObjects< Iterator, ScratchData, CopyData > ScratchAndCopyDataObjects
Definition: work_stream.h:906
const std::function< void(const CopyData &)> copier
Definition: work_stream.h:927
IteratorRangeToItemStream(const Iterator &begin, const Iterator &end, const unsigned int buffer_size, const unsigned int chunk_size, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data)
Definition: work_stream.h:323
Threads::ThreadLocalStorage< typename ItemType::ScratchDataList > thread_local_scratch
Definition: work_stream.h:446
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:402
#define DEAL_II_TBB_WITH_ONEAPI
Definition: config.h:76
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:403
#define Assert(cond, exc)
Definition: exceptions.h:1465
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcMessage(std::string arg1)
constexpr int chunk_size
Definition: cuda_size.h:35
void handle_std_exception(const std::exception &exc)
VectorType::value_type * end(VectorType &V)
VectorType::value_type * begin(VectorType &V)
void run(const Iterator &begin, const typename identity< Iterator >::type &end, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data)
Definition: work_stream.h:660
void run(const std::vector< std::vector< Iterator > > &colored_iterators, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const unsigned int chunk_size)
Definition: work_stream.h:945
void run(const Iterator &begin, const typename identity< Iterator >::type &end, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const unsigned int queue_length, const unsigned int chunk_size)
Definition: work_stream.h:472
void run(const std::vector< std::vector< Iterator > > &colored_iterators, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const unsigned int queue_length=2 *MultithreadInfo::n_threads(), const unsigned int chunk_size=8)
Definition: work_stream.h:1252
void parallel_for(Iterator x_begin, Iterator x_end, const Functor &functor, const unsigned int grainsize)
Definition: parallel.h:158
STL namespace.
ScratchAndCopyDataObjects(const ScratchAndCopyDataObjects &)
Definition: work_stream.h:778
ScratchAndCopyDataObjects(std::unique_ptr< ScratchData > &&p, std::unique_ptr< CopyData > &&q, const bool in_use)
Definition: work_stream.h:767
Threads::ThreadLocalStorage< ScratchDataList > * scratch_data
Definition: work_stream.h:290