Reference documentation for deal.II version Git 92c1895bf8 2020-06-04 17:48:28 -0400
\(\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 
25 # include <deal.II/base/parallel.h>
29 
30 # ifdef DEAL_II_WITH_TBB
31 # include <tbb/pipeline.h>
32 # endif
33 
34 # include <functional>
35 # include <iterator>
36 # include <memory>
37 # include <utility>
38 # include <vector>
39 
41 
42 
43 
157 namespace WorkStream
158 {
159 # ifdef DEAL_II_WITH_TBB
160 
161  namespace internal
162  {
175  namespace Implementation2
176  {
180  template <typename Iterator, typename ScratchData, typename CopyData>
181  class IteratorRangeToItemStream : public tbb::filter
182  {
183  public:
190  struct ItemType
191  {
198  {
199  std::unique_ptr<ScratchData> scratch_data;
201 
206  : currently_in_use(false)
207  {}
208 
209  ScratchDataObject(ScratchData *p, const bool in_use)
210  : scratch_data(p)
211  , currently_in_use(in_use)
212  {}
213 
214  // Provide a copy constructor that actually doesn't copy the
215  // internal state. This makes handling ScratchAndCopyDataObjects
216  // easier to handle with STL containers.
218  : currently_in_use(false)
219  {}
220 
221  ScratchDataObject(ScratchDataObject &&o) noexcept = default;
222  };
223 
224 
229  using ScratchDataList = std::list<ScratchDataObject>;
230 
235  std::vector<Iterator> work_items;
236 
242  std::vector<CopyData> copy_datas;
243 
249  unsigned int n_items;
250 
283 
288  const ScratchData *sample_scratch_data;
289 
295 
296 
302  : n_items(0)
303  , scratch_data(nullptr)
304  , sample_scratch_data(nullptr)
305  , currently_in_use(false)
306  {}
307  };
308 
309 
316  const Iterator & end,
317  const unsigned int buffer_size,
318  const unsigned int chunk_size,
319  const ScratchData &sample_scratch_data,
320  const CopyData & sample_copy_data)
321  : tbb::filter(/*is_serial=*/true)
322  , remaining_iterator_range(begin, end)
323  , item_buffer(buffer_size)
324  , sample_scratch_data(sample_scratch_data)
325  , chunk_size(chunk_size)
326  {
327  // initialize the elements of the ring buffer
328  for (unsigned int element = 0; element < item_buffer.size();
329  ++element)
330  {
331  Assert(item_buffer[element].n_items == 0, ExcInternalError());
332 
333  item_buffer[element].work_items.resize(
334  chunk_size, remaining_iterator_range.second);
335  item_buffer[element].scratch_data = &thread_local_scratch;
336  item_buffer[element].sample_scratch_data = &sample_scratch_data;
337  item_buffer[element].copy_datas.resize(chunk_size,
338  sample_copy_data);
339  item_buffer[element].currently_in_use = false;
340  }
341  }
342 
343 
347  virtual void *
348  operator()(void *) override
349  {
350  // find first unused item. we know that there must be one
351  // because we have set the maximal number of tokens in flight
352  // and have set the ring buffer to have exactly this size. so
353  // if this function is called, we know that less than the
354  // maximal number of items in currently in flight
355  //
356  // note that we need not lock access to this array since
357  // the current stage is run sequentially and we can therefore
358  // enter the following block only once at any given time.
359  // thus, there can be no race condition between checking that
360  // a flag is false and setting it to true. (there may be
361  // another thread where we release items and set 'false'
362  // flags to 'true', but that too does not produce any
363  // problems)
364  ItemType *current_item = nullptr;
365  for (unsigned int i = 0; i < item_buffer.size(); ++i)
366  if (item_buffer[i].currently_in_use == false)
367  {
368  item_buffer[i].currently_in_use = true;
369  current_item = &item_buffer[i];
370  break;
371  }
372  Assert(current_item != nullptr,
373  ExcMessage("This can't be. There must be a free item!"));
374 
375  // initialize the next item. it may
376  // consist of at most chunk_size
377  // elements
378  current_item->n_items = 0;
379  while ((remaining_iterator_range.first !=
380  remaining_iterator_range.second) &&
381  (current_item->n_items < chunk_size))
382  {
383  current_item->work_items[current_item->n_items] =
385 
386  ++remaining_iterator_range.first;
387  ++current_item->n_items;
388  }
389 
390  if (current_item->n_items == 0)
391  // there were no items
392  // left. terminate the pipeline
393  return nullptr;
394  else
395  return current_item;
396  }
397 
398  private:
403  std::pair<Iterator, Iterator> remaining_iterator_range;
404 
408  std::vector<ItemType> item_buffer;
409 
442 
448  const ScratchData &sample_scratch_data;
449 
456  const unsigned int chunk_size;
457  };
458 
459 
460 
466  template <typename Iterator, typename ScratchData, typename CopyData>
467  class Worker : public tbb::filter
468  {
469  public:
476  const std::function<void(const Iterator &, ScratchData &, CopyData &)>
477  & worker,
478  bool copier_exist = true)
479  : tbb::filter(/* is_serial= */ false)
480  , worker(worker)
481  , copier_exist(copier_exist)
482  {}
483 
484 
488  void *
489  operator()(void *item) override
490  {
491  // first unpack the current item
492  using ItemType =
494  ScratchData,
495  CopyData>::ItemType;
496 
497  ItemType *current_item = static_cast<ItemType *>(item);
498 
499  // we need to find an unused scratch data object in the list that
500  // corresponds to the current thread and then mark it as used. if
501  // we can't find one, create one
502  //
503  // as discussed in the discussion of the documentation of the
504  // IteratorRangeToItemStream::scratch_data variable, there is no
505  // need to synchronize access to this variable using a mutex
506  // as long as we have no yield-point in between. this means that
507  // we can't take an iterator into the list now and expect it to
508  // still be valid after calling the worker, but we at least do
509  // not have to lock the following section
510  ScratchData *scratch_data = nullptr;
511  {
512  typename ItemType::ScratchDataList &scratch_data_list =
513  current_item->scratch_data->get();
514 
515  // see if there is an unused object. if so, grab it and mark
516  // it as used
517  for (typename ItemType::ScratchDataList::iterator p =
518  scratch_data_list.begin();
519  p != scratch_data_list.end();
520  ++p)
521  if (p->currently_in_use == false)
522  {
523  scratch_data = p->scratch_data.get();
524  p->currently_in_use = true;
525  break;
526  }
527 
528  // if no object was found, create one and mark it as used
529  if (scratch_data == nullptr)
530  {
531  scratch_data =
532  new ScratchData(*current_item->sample_scratch_data);
533 
534  typename ItemType::ScratchDataList::value_type
535  new_scratch_object(scratch_data, true);
536  scratch_data_list.push_back(std::move(new_scratch_object));
537  }
538  }
539 
540  // then call the worker function on each element of the chunk we were
541  // given. since these worker functions are called on separate threads,
542  // nothing good can happen if they throw an exception and we are best
543  // off catching it and showing an error message
544  for (unsigned int i = 0; i < current_item->n_items; ++i)
545  {
546  try
547  {
548  if (worker)
549  worker(current_item->work_items[i],
550  *scratch_data,
551  current_item->copy_datas[i]);
552  }
553  catch (const std::exception &exc)
554  {
556  }
557  catch (...)
558  {
560  }
561  }
562 
563  // finally mark the scratch object as unused again. as above, there
564  // is no need to lock anything here since the object we work on
565  // is thread-local
566  {
567  typename ItemType::ScratchDataList &scratch_data_list =
568  current_item->scratch_data->get();
569 
570  for (typename ItemType::ScratchDataList::iterator p =
571  scratch_data_list.begin();
572  p != scratch_data_list.end();
573  ++p)
574  if (p->scratch_data.get() == scratch_data)
575  {
576  Assert(p->currently_in_use == true, ExcInternalError());
577  p->currently_in_use = false;
578  }
579  }
580 
581  // if there is no copier, mark current item as usable again
582  if (copier_exist == false)
583  current_item->currently_in_use = false;
584 
585 
586  // then return the original pointer
587  // to the now modified object
588  return item;
589  }
590 
591 
592  private:
597  const std::function<void(const Iterator &, ScratchData &, CopyData &)>
599 
605  };
606 
607 
608 
614  template <typename Iterator, typename ScratchData, typename CopyData>
615  class Copier : public tbb::filter
616  {
617  public:
624  Copier(const std::function<void(const CopyData &)> &copier)
625  : tbb::filter(/*is_serial=*/true)
626  , copier(copier)
627  {}
628 
629 
633  void *
634  operator()(void *item) override
635  {
636  // first unpack the current item
637  using ItemType =
639  ScratchData,
640  CopyData>::ItemType;
641 
642  ItemType *current_item = static_cast<ItemType *>(item);
643 
644  // initiate copying data. for the same reasons as in the worker class
645  // above, catch exceptions rather than letting it propagate into
646  // unknown territories
647  for (unsigned int i = 0; i < current_item->n_items; ++i)
648  {
649  try
650  {
651  if (copier)
652  copier(current_item->copy_datas[i]);
653  }
654  catch (const std::exception &exc)
655  {
657  }
658  catch (...)
659  {
661  }
662  }
663 
664  // mark current item as usable again
665  current_item->currently_in_use = false;
666 
667 
668  // return an invalid item since we are at the end of the
669  // pipeline
670  return nullptr;
671  }
672 
673 
674  private:
678  const std::function<void(const CopyData &)> copier;
679  };
680 
681  } // namespace Implementation2
682 
683 
691  namespace Implementation3
692  {
698  template <typename Iterator, typename ScratchData, typename CopyData>
700  {
701  std::unique_ptr<ScratchData> scratch_data;
702  std::unique_ptr<CopyData> copy_data;
704 
709  : currently_in_use(false)
710  {}
711 
713  CopyData * q,
714  const bool in_use)
715  : scratch_data(p)
716  , copy_data(q)
717  , currently_in_use(in_use)
718  {}
719 
720  // Provide a copy constructor that actually doesn't copy the
721  // internal state. This makes handling ScratchAndCopyDataObjects
722  // easier to handle with STL containers.
724  : currently_in_use(false)
725  {}
726  };
727 
728 
729 
735  template <typename Iterator, typename ScratchData, typename CopyData>
737  {
738  public:
743  const std::function<void(const Iterator &, ScratchData &, CopyData &)>
744  & worker,
745  const std::function<void(const CopyData &)> &copier,
746  const ScratchData & sample_scratch_data,
747  const CopyData & sample_copy_data)
748  : worker(worker)
749  , copier(copier)
750  , sample_scratch_data(sample_scratch_data)
751  , sample_copy_data(sample_copy_data)
752  {}
753 
754 
759  void
760  operator()(const tbb::blocked_range<
761  typename std::vector<Iterator>::const_iterator> &range)
762  {
763  // we need to find an unused scratch and corresponding copy
764  // data object in the list that corresponds to the current
765  // thread and then mark it as used. If we can't find one,
766  // create one as discussed in the discussion of the documentation
767  // of the IteratorRangeToItemStream::scratch_data variable,
768  // there is no need to synchronize access to this variable
769  // using a mutex as long as we have no yield-point in between.
770  // This means that we can't take an iterator into the list
771  // now and expect it to still be valid after calling the worker,
772  // but we at least do not have to lock the following section.
773  ScratchData *scratch_data = nullptr;
774  CopyData * copy_data = nullptr;
775  {
776  ScratchAndCopyDataList &scratch_and_copy_data_list = data.get();
777 
778  // see if there is an unused object. if so, grab it and mark
779  // it as used
780  for (typename ScratchAndCopyDataList::iterator p =
781  scratch_and_copy_data_list.begin();
782  p != scratch_and_copy_data_list.end();
783  ++p)
784  if (p->currently_in_use == false)
785  {
786  scratch_data = p->scratch_data.get();
787  copy_data = p->copy_data.get();
788  p->currently_in_use = true;
789  break;
790  }
791 
792  // if no element in the list was found, create one and mark it as
793  // used
794  if (scratch_data == nullptr)
795  {
796  Assert(copy_data == nullptr, ExcInternalError());
797  scratch_data = new ScratchData(sample_scratch_data);
798  copy_data = new CopyData(sample_copy_data);
799 
800  scratch_and_copy_data_list.emplace_back(scratch_data,
801  copy_data,
802  true);
803  }
804  }
805 
806  // then call the worker and copier functions on each
807  // element of the chunk we were given.
808  for (typename std::vector<Iterator>::const_iterator p = range.begin();
809  p != range.end();
810  ++p)
811  {
812  try
813  {
814  if (worker)
815  worker(*p, *scratch_data, *copy_data);
816  if (copier)
817  copier(*copy_data);
818  }
819  catch (const std::exception &exc)
820  {
822  }
823  catch (...)
824  {
826  }
827  }
828 
829  // finally mark the scratch object as unused again. as above, there
830  // is no need to lock anything here since the object we work on
831  // is thread-local
832  {
833  ScratchAndCopyDataList &scratch_and_copy_data_list = data.get();
834 
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->scratch_data.get() == scratch_data)
840  {
841  Assert(p->currently_in_use == true, ExcInternalError());
842  p->currently_in_use = false;
843  }
844  }
845  }
846 
847  private:
848  using ScratchAndCopyDataObjects = typename Implementation3::
849  ScratchAndCopyDataObjects<Iterator, ScratchData, CopyData>;
850 
855  using ScratchAndCopyDataList = std::list<ScratchAndCopyDataObjects>;
856 
858 
863  const std::function<void(const Iterator &, ScratchData &, CopyData &)>
865 
870  const std::function<void(const CopyData &)> copier;
871 
875  const ScratchData &sample_scratch_data;
876  const CopyData & sample_copy_data;
877  };
878  } // namespace Implementation3
879 
880  } // namespace internal
881 
882 
883 # endif // DEAL_II_WITH_TBB
884 
885 
933  template <typename Worker,
934  typename Copier,
935  typename Iterator,
936  typename ScratchData,
937  typename CopyData>
938  void
939  run(const std::vector<std::vector<Iterator>> &colored_iterators,
940  Worker worker,
941  Copier copier,
942  const ScratchData & sample_scratch_data,
943  const CopyData & sample_copy_data,
944  const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
945  const unsigned int chunk_size = 8);
946 
947 
997  template <typename Worker,
998  typename Copier,
999  typename Iterator,
1000  typename ScratchData,
1001  typename CopyData>
1002  void
1003  run(const Iterator & begin,
1004  const typename identity<Iterator>::type &end,
1005  Worker worker,
1006  Copier copier,
1007  const ScratchData & sample_scratch_data,
1008  const CopyData & sample_copy_data,
1009  const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
1010  const unsigned int chunk_size = 8)
1011  {
1012  Assert(queue_length > 0,
1013  ExcMessage("The queue length must be at least one, and preferably "
1014  "larger than the number of processors on this system."));
1015  (void)queue_length; // removes -Wunused-parameter warning in optimized mode
1016  Assert(chunk_size > 0, ExcMessage("The chunk_size must be at least one."));
1017  (void)chunk_size; // removes -Wunused-parameter warning in optimized mode
1018 
1019  // if no work then skip. (only use operator!= for iterators since we may
1020  // not have an equality comparison operator)
1021  if (!(begin != end))
1022  return;
1023 
1024  // we want to use TBB if we have support and if it is not disabled at
1025  // runtime:
1026 # ifdef DEAL_II_WITH_TBB
1027  if (MultithreadInfo::n_threads() == 1)
1028 # endif
1029  {
1030  // need to copy the sample since it is marked const
1031  ScratchData scratch_data = sample_scratch_data;
1032  CopyData copy_data = sample_copy_data; // NOLINT
1033 
1034  for (Iterator i = begin; i != end; ++i)
1035  {
1036  // need to check if the function is not the zero function. To
1037  // check zero-ness, create a C++ function out of it and check that
1038  if (static_cast<const std::function<
1039  void(const Iterator &, ScratchData &, CopyData &)> &>(worker))
1040  worker(i, scratch_data, copy_data);
1041  if (static_cast<const std::function<void(const CopyData &)> &>(
1042  copier))
1043  copier(copy_data);
1044  }
1045  }
1046 # ifdef DEAL_II_WITH_TBB
1047  else // have TBB and use more than one thread
1048  {
1049  // Check that the copier exist
1050  if (static_cast<const std::function<void(const CopyData &)> &>(copier))
1051  {
1052  // create the three stages of the pipeline
1053  internal::Implementation2::
1054  IteratorRangeToItemStream<Iterator, ScratchData, CopyData>
1055  iterator_range_to_item_stream(begin,
1056  end,
1057  queue_length,
1058  chunk_size,
1059  sample_scratch_data,
1060  sample_copy_data);
1061 
1063  worker_filter(worker);
1065  copier_filter(copier);
1066 
1067  // now create a pipeline from these stages
1068  tbb::pipeline assembly_line;
1069  assembly_line.add_filter(iterator_range_to_item_stream);
1070  assembly_line.add_filter(worker_filter);
1071  assembly_line.add_filter(copier_filter);
1072 
1073  // and run it
1074  assembly_line.run(queue_length);
1075 
1076  assembly_line.clear();
1077  }
1078  else
1079  {
1080  // there is no copier function. in this case, we have an
1081  // embarrassingly parallel problem where we can
1082  // essentially apply parallel_for. because parallel_for
1083  // requires subdividing the range for which operator- is
1084  // necessary between iterators, it is often inefficient to
1085  // apply it directly to cell ranges and similar iterator
1086  // types for which operator- is expensive or, in fact,
1087  // nonexistent. rather, in that case, we simply copy the
1088  // iterators into a large array and use operator- on
1089  // iterators to this array of iterators.
1090  //
1091  // instead of duplicating code, this is essentially the
1092  // same situation we have in Implementation3 below, so we
1093  // just defer to that place
1094  std::vector<std::vector<Iterator>> all_iterators(1);
1095  for (Iterator p = begin; p != end; ++p)
1096  all_iterators[0].push_back(p);
1097 
1098  run(all_iterators,
1099  worker,
1100  copier,
1101  sample_scratch_data,
1102  sample_copy_data,
1103  queue_length,
1104  chunk_size);
1105  }
1106  }
1107 # endif
1108  }
1109 
1110 
1111 
1119  template <typename Worker,
1120  typename Copier,
1121  typename IteratorRangeType,
1122  typename ScratchData,
1123  typename CopyData,
1124  typename = typename std::enable_if<
1126  void
1127  run(IteratorRangeType iterator_range,
1128  Worker worker,
1129  Copier copier,
1130  const ScratchData &sample_scratch_data,
1131  const CopyData & sample_copy_data,
1132  const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
1133  const unsigned int chunk_size = 8)
1134  {
1135  // Call the function above
1136  run(iterator_range.begin(),
1137  iterator_range.end(),
1138  worker,
1139  copier,
1141  sample_copy_data,
1142  queue_length,
1143  chunk_size);
1144  }
1145 
1146 
1147 
1151  template <typename Worker,
1152  typename Copier,
1153  typename Iterator,
1154  typename ScratchData,
1155  typename CopyData>
1156  void
1157  run(const IteratorRange<Iterator> &iterator_range,
1158  Worker worker,
1159  Copier copier,
1160  const ScratchData & sample_scratch_data,
1161  const CopyData & sample_copy_data,
1162  const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
1163  const unsigned int chunk_size = 8)
1164  {
1165  // Call the function above
1166  run(iterator_range.begin(),
1167  iterator_range.end(),
1168  worker,
1169  copier,
1171  sample_copy_data,
1172  queue_length,
1173  chunk_size);
1174  }
1175 
1176 
1177  // Implementation 3:
1178  template <typename Worker,
1179  typename Copier,
1180  typename Iterator,
1181  typename ScratchData,
1182  typename CopyData>
1183  void
1184  run(const std::vector<std::vector<Iterator>> &colored_iterators,
1185  Worker worker,
1186  Copier copier,
1187  const ScratchData & sample_scratch_data,
1188  const CopyData & sample_copy_data,
1189  const unsigned int queue_length,
1190  const unsigned int chunk_size)
1191  {
1192  Assert(queue_length > 0,
1193  ExcMessage("The queue length must be at least one, and preferably "
1194  "larger than the number of processors on this system."));
1195  (void)queue_length; // removes -Wunused-parameter warning in optimized mode
1196  Assert(chunk_size > 0, ExcMessage("The chunk_size must be at least one."));
1197  (void)chunk_size; // removes -Wunused-parameter warning in optimized mode
1198 
1199  // we want to use TBB if we have support and if it is not disabled at
1200  // runtime:
1201 # ifdef DEAL_II_WITH_TBB
1202  if (MultithreadInfo::n_threads() == 1)
1203 # endif
1204  {
1205  // need to copy the sample since it is marked const
1206  ScratchData scratch_data = sample_scratch_data;
1207  CopyData copy_data = sample_copy_data; // NOLINT
1208 
1209  for (unsigned int color = 0; color < colored_iterators.size(); ++color)
1210  for (typename std::vector<Iterator>::const_iterator p =
1211  colored_iterators[color].begin();
1212  p != colored_iterators[color].end();
1213  ++p)
1214  {
1215  // need to check if the function is not the zero function. To
1216  // check zero-ness, create a C++ function out of it and check that
1217  if (static_cast<const std::function<void(
1218  const Iterator &, ScratchData &, CopyData &)> &>(worker))
1219  worker(*p, scratch_data, copy_data);
1220  if (static_cast<const std::function<void(const CopyData &)> &>(
1221  copier))
1222  copier(copy_data);
1223  }
1224  }
1225 # ifdef DEAL_II_WITH_TBB
1226  else // have TBB and use more than one thread
1227  {
1228  // loop over the various colors of what we're given
1229  for (unsigned int color = 0; color < colored_iterators.size(); ++color)
1230  if (colored_iterators[color].size() > 0)
1231  {
1232  using WorkerAndCopier = internal::Implementation3::
1233  WorkerAndCopier<Iterator, ScratchData, CopyData>;
1234 
1235  using RangeType = typename std::vector<Iterator>::const_iterator;
1236 
1237  WorkerAndCopier worker_and_copier(worker,
1238  copier,
1239  sample_scratch_data,
1240  sample_copy_data);
1241 
1243  colored_iterators[color].begin(),
1244  colored_iterators[color].end(),
1245  [&worker_and_copier](
1246  const tbb::blocked_range<
1247  typename std::vector<Iterator>::const_iterator> &range) {
1248  worker_and_copier(range);
1249  },
1250  chunk_size);
1251  }
1252  }
1253 # endif
1254  }
1255 
1256 
1257 
1299  template <typename MainClass,
1300  typename Iterator,
1301  typename ScratchData,
1302  typename CopyData>
1303  void
1304  run(const Iterator & begin,
1305  const typename identity<Iterator>::type &end,
1306  MainClass & main_object,
1307  void (MainClass::*worker)(const Iterator &, ScratchData &, CopyData &),
1308  void (MainClass::*copier)(const CopyData &),
1309  const ScratchData &sample_scratch_data,
1310  const CopyData & sample_copy_data,
1311  const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
1312  const unsigned int chunk_size = 8)
1313  {
1314  // forward to the other function
1315  run(begin,
1316  end,
1317  [&main_object, worker](const Iterator &iterator,
1318  ScratchData & scratch_data,
1319  CopyData & copy_data) {
1320  (main_object.*worker)(iterator, scratch_data, copy_data);
1321  },
1322  [&main_object, copier](const CopyData &copy_data) {
1323  (main_object.*copier)(copy_data);
1324  },
1326  sample_copy_data,
1327  queue_length,
1328  chunk_size);
1329  }
1330 
1331 
1332  template <typename MainClass,
1333  typename Iterator,
1334  typename ScratchData,
1335  typename CopyData>
1336  void
1338  const IteratorOverIterators<typename identity<Iterator>::type> &end,
1339  MainClass &main_object,
1340  void (MainClass::*worker)(const Iterator &, ScratchData &, CopyData &),
1341  void (MainClass::*copier)(const CopyData &),
1342  const ScratchData &sample_scratch_data,
1343  const CopyData & sample_copy_data,
1344  const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
1345  const unsigned int chunk_size = 8)
1346  {
1347  // forward to the other function
1348  run(begin,
1349  end,
1350  [&main_object, worker](const Iterator &iterator,
1351  ScratchData & scratch_data,
1352  CopyData & copy_data) {
1353  (main_object.*worker)(iterator, scratch_data, copy_data);
1354  },
1355  [&main_object, copier](const CopyData &copy_data) {
1356  (main_object.*copier)(copy_data);
1357  },
1359  sample_copy_data,
1360  queue_length,
1361  chunk_size);
1362  }
1363 
1364 
1365 
1373  template <typename MainClass,
1374  typename IteratorRangeType,
1375  typename ScratchData,
1376  typename CopyData,
1377  typename = typename std::enable_if<
1379  void
1380  run(IteratorRangeType iterator_range,
1381  MainClass & main_object,
1382  void (MainClass::*worker)(
1384  ScratchData &,
1385  CopyData &),
1386  void (MainClass::*copier)(const CopyData &),
1387  const ScratchData &sample_scratch_data,
1388  const CopyData & sample_copy_data,
1389  const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
1390  const unsigned int chunk_size = 8)
1391  {
1392  // Call the function above
1393  run(std::begin(iterator_range),
1394  std::end(iterator_range),
1395  main_object,
1396  worker,
1397  copier,
1398  sample_scratch_data,
1399  sample_copy_data,
1400  queue_length,
1401  chunk_size);
1402  }
1403 
1404 
1405 
1409  template <typename MainClass,
1410  typename Iterator,
1411  typename ScratchData,
1412  typename CopyData>
1413  void
1415  MainClass & main_object,
1416  void (MainClass::*worker)(const Iterator &, ScratchData &, CopyData &),
1417  void (MainClass::*copier)(const CopyData &),
1418  const ScratchData &sample_scratch_data,
1419  const CopyData & sample_copy_data,
1420  const unsigned int queue_length = 2 * MultithreadInfo::n_threads(),
1421  const unsigned int chunk_size = 8)
1422  {
1423  // Call the function above
1424  run(std::begin(iterator_range),
1425  std::end(iterator_range),
1426  main_object,
1427  worker,
1428  copier,
1429  sample_scratch_data,
1430  sample_copy_data,
1431  queue_length,
1432  chunk_size);
1433  }
1434 
1435 } // namespace WorkStream
1436 
1437 
1438 
1440 
1441 
1442 
1443 //---------------------------- work_stream.h ---------------------------
1444 // end of #ifndef dealii_work_stream_h
1445 #endif
1446 //---------------------------- work_stream.h ---------------------------
void * operator()(void *item) override
Definition: work_stream.h:634
typename Implementation3::ScratchAndCopyDataObjects< Iterator, ScratchData, CopyData > ScratchAndCopyDataObjects
Definition: work_stream.h:849
const std::function< void(const Iterator &, ScratchData &, CopyData &)> worker
Definition: work_stream.h:598
const std::function< void(const CopyData &)> copier
Definition: work_stream.h:870
std::list< ScratchAndCopyDataObjects > ScratchAndCopyDataList
Definition: work_stream.h:855
IteratorOverIterators begin()
ScratchAndCopyDataObjects(ScratchData *p, CopyData *q, const bool in_use)
Definition: work_stream.h:712
void parallel_for(Iterator x_begin, Iterator x_end, const Functor &functor, const unsigned int grainsize)
Definition: parallel.h:156
const std::function< void(const Iterator &, ScratchData &, CopyData &)> worker
Definition: work_stream.h:864
void * operator()(void *item) override
Definition: work_stream.h:489
void operator()(const tbb::blocked_range< typename std::vector< Iterator >::const_iterator > &range)
Definition: work_stream.h:760
Threads::ThreadLocalStorage< ScratchDataList > * scratch_data
Definition: work_stream.h:282
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:315
static ::ExceptionBase & ExcMessage(std::string arg1)
#define Assert(cond, exc)
Definition: exceptions.h:1408
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:361
VectorType::value_type * end(VectorType &V)
Worker(const std::function< void(const Iterator &, ScratchData &, CopyData &)> &worker, bool copier_exist=true)
Definition: work_stream.h:475
MatrixTableIterators::Iterator< TransposeTable< T >, Constness, MatrixTableIterators::Storage::column_major > Iterator
Definition: table.h:1922
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:360
VectorType::value_type * begin(VectorType &V)
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:742
const std::function< void(const CopyData &)> copier
Definition: work_stream.h:678
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:1184
static unsigned int n_threads()
Threads::ThreadLocalStorage< typename ItemType::ScratchDataList > thread_local_scratch
Definition: work_stream.h:441
void handle_std_exception(const std::exception &exc)
Copier(const std::function< void(const CopyData &)> &copier)
Definition: work_stream.h:624
ScratchAndCopyDataObjects(const ScratchAndCopyDataObjects &)
Definition: work_stream.h:723
Threads::ThreadLocalStorage< ScratchAndCopyDataList > data
Definition: work_stream.h:857
static ::ExceptionBase & ExcInternalError()
IteratorOverIterators end() const