13#ifndef dealii_work_stream_h
14# define dealii_work_stream_h
29# ifdef DEAL_II_WITH_TBB
30# ifdef DEAL_II_TBB_WITH_ONEAPI
31# include <tbb/parallel_pipeline.h>
33# include <tbb/pipeline.h>
35# include <tbb/blocked_range.h>
38# ifdef DEAL_II_WITH_TASKFLOW
39# include <taskflow/taskflow.hpp>
178 template <
typename Iterator,
typename ScratchData,
typename CopyData>
193 std::unique_ptr<CopyData> &&q,
213 template <
typename ScratchData>
246# ifdef DEAL_II_WITH_TBB
261 namespace tbb_no_coloring
266 template <
typename Iterator,
typename ScratchData,
typename CopyData>
370 const unsigned int buffer_size,
373 const CopyData &sample_copy_data)
388 item.copy_datas.resize(
chunk_size, sample_copy_data);
389 item.currently_in_use =
false;
415 for (
unsigned int i = 0; i <
item_buffer.size(); ++i)
422 Assert(current_item !=
nullptr,
423 ExcMessage(
"This can't be. There must be a free item!"));
511 template <
typename Worker,
514 typename ScratchData,
521 const ScratchData &sample_scratch_data,
522 const CopyData &sample_copy_data,
523 const unsigned int queue_length,
524 const unsigned int chunk_size)
538 iterator_range_to_item_stream(
begin,
544 auto item_generator = [&](tbb::flow_control &fc) -> ItemType * {
545 if (
const auto item = iterator_range_to_item_stream.
get_item())
561 std::function<void(const Iterator &, ScratchData &, CopyData &)>(
564 static_cast<bool>(std::function<void(const CopyData &)>(copier))](
565 ItemType *current_item) {
577 ScratchData *scratch_data =
nullptr;
581 for (
auto &p : current_item->scratch_data->get())
582 if (p.currently_in_use ==
false)
584 scratch_data = p.scratch_data.get();
585 p.currently_in_use =
true;
591 if (scratch_data ==
nullptr)
594 new ScratchData(*current_item->sample_scratch_data);
595 current_item->scratch_data->get().emplace_back(scratch_data,
604 for (
unsigned int i = 0; i < current_item->n_iterators; ++i)
609 worker(current_item->iterators[i],
611 current_item->copy_datas[i]);
613 catch (
const std::exception &exc)
626 for (
auto &p : current_item->scratch_data->get())
627 if (p.scratch_data.get() == scratch_data)
630 p.currently_in_use =
false;
636 if (copier_exists ==
false)
637 current_item->currently_in_use =
false;
650 auto item_copier = [copier = std::function<void(const CopyData &)>(
651 copier)](ItemType *current_item) {
657 for (
unsigned int i = 0; i < current_item->n_iterators; ++i)
661 copier(current_item->copy_datas[i]);
663 catch (
const std::exception &exc)
674 current_item->currently_in_use =
false;
679 auto tbb_item_stream_filter = tbb::make_filter<void, ItemType *>(
681 tbb::filter_mode::serial_in_order,
687 auto tbb_worker_filter = tbb::make_filter<ItemType *, ItemType *>(
689 tbb::filter_mode::parallel,
691 tbb::filter::parallel,
695 auto tbb_copier_filter = tbb::make_filter<ItemType *, void>(
697 tbb::filter_mode::serial_in_order,
703 tbb::parallel_pipeline(queue_length,
704 tbb_item_stream_filter & tbb_worker_filter &
713# ifdef DEAL_II_WITH_TASKFLOW
721 namespace taskflow_no_coloring
729 template <
typename Worker,
732 typename ScratchData,
739 const ScratchData &sample_scratch_data,
740 const CopyData &sample_copy_data,
741 const unsigned int = 2 *
743 const unsigned int chunk_size = 8)
747 tf::Taskflow taskflow;
750 thread_safe_scratch_datas;
752 tf::Task last_copier;
761 std::vector<CopyData> copy_datas;
763 CopyChunk(
const unsigned int chunk_size,
764 const CopyData &sample_copy_data)
765 : copy_datas(chunk_size, sample_copy_data)
771 std::size_t chunk_no = 0;
776 std::vector<std::unique_ptr<CopyChunk>> copy_chunks;
781 for (Iterator it =
begin; it !=
end;)
789 std::size_t current_chunk_size = 0;
790 Iterator current_chunk_start = it;
791 for (
unsigned int i = 0; (i < chunk_size) && (it !=
end); ++it, ++i)
792 ++current_chunk_size;
796 .emplace([current_chunk_start,
799 &thread_safe_scratch_datas,
800 &sample_scratch_data,
804 ScratchData *scratch_data =
nullptr;
806 auto &scratch_datas = thread_safe_scratch_datas.
get();
812 for (
auto &p : scratch_datas)
814 if (p.currently_in_use ==
false)
816 scratch_data = p.scratch_data.get();
817 p.currently_in_use =
true;
823 if (scratch_data ==
nullptr)
825 scratch_datas.emplace_back(std::make_unique<ScratchData>(
826 sample_scratch_data),
828 scratch_data = scratch_datas.back().scratch_data.get();
833 copy_chunks[chunk_no] =
834 std::make_unique<CopyChunk>(current_chunk_size,
836 auto ©_chunk = copy_chunks[chunk_no];
837 auto it = current_chunk_start;
838 for (std::size_t i = 0; i < current_chunk_size; ++i)
840 worker(it, *scratch_data, (copy_chunk->copy_datas)[i]);
846 for (
auto &p : scratch_datas)
848 if (p.scratch_data.get() == scratch_data)
850 Assert(p.currently_in_use ==
true,
852 p.currently_in_use =
false;
860 tf::Task copier_task =
862 .emplace([chunk_no, ©_chunks, &copier]() {
863 auto copy_chunk = copy_chunks[chunk_no].get();
864 for (
auto ©_data : copy_chunk->copy_datas)
869 copy_chunks[chunk_no].reset();
874 worker_task.precede(copier_task);
879 if (!last_copier.empty())
880 last_copier.precede(copier_task);
885 last_copier = copier_task;
888 copy_chunks.resize(chunk_no);
896 if (executor.this_worker_id() != -1)
897 executor.corun(taskflow);
899 executor.run(taskflow).wait();
915 template <
typename Worker,
918 typename ScratchData,
925 const ScratchData &sample_scratch_data,
926 const CopyData &sample_copy_data)
929 ScratchData scratch_data = sample_scratch_data;
930 CopyData copy_data = sample_copy_data;
934 const bool have_worker =
935 (
static_cast<const std::function<
936 void(
const Iterator &, ScratchData &, CopyData &)
> &>(worker)) !=
938 const bool have_copier =
939 (
static_cast<const std::function<
void(
const CopyData &)
> &>(
943 for (Iterator i =
begin; i !=
end; ++i)
946 worker(i, scratch_data, copy_data);
957 template <
typename Worker,
960 typename ScratchData,
963 run(
const std::vector<std::vector<Iterator>> &colored_iterators,
966 const ScratchData &sample_scratch_data,
967 const CopyData &sample_copy_data)
970 ScratchData scratch_data = sample_scratch_data;
971 CopyData copy_data = sample_copy_data;
975 const bool have_worker =
976 (
static_cast<const std::function<
977 void(
const Iterator &, ScratchData &, CopyData &)
> &>(worker)) !=
979 const bool have_copier =
980 (
static_cast<const std::function<
void(
const CopyData &)
> &>(
984 for (
unsigned int color = 0; color < colored_iterators.size(); ++color)
985 if (colored_iterators[color].
size() > 0)
986 for (
auto &it : colored_iterators[color])
989 worker(it, scratch_data, copy_data);
999# ifdef DEAL_II_WITH_TBB
1007 namespace tbb_colored
1014 template <
typename Iterator,
typename ScratchData,
typename CopyData>
1022 const std::function<
void(
const Iterator &, ScratchData &, CopyData &)>
1024 const std::function<
void(
const CopyData &)> &
copier,
1040 typename std::vector<Iterator>::const_iterator> &range)
1052 ScratchData *scratch_data =
nullptr;
1053 CopyData *copy_data =
nullptr;
1059 for (
typename ScratchAndCopyDataList::iterator p =
1060 scratch_and_copy_data_list.begin();
1061 p != scratch_and_copy_data_list.end();
1063 if (p->currently_in_use ==
false)
1065 scratch_data = p->scratch_data.get();
1066 copy_data = p->copy_data.get();
1067 p->currently_in_use =
true;
1073 if (scratch_data ==
nullptr)
1077 scratch_and_copy_data_list.emplace_back(
1082 scratch_and_copy_data_list.back().scratch_data.get();
1083 copy_data = scratch_and_copy_data_list.back().copy_data.get();
1089 for (
typename std::vector<Iterator>::const_iterator p = range.begin();
1096 worker(*p, *scratch_data, *copy_data);
1100 catch (
const std::exception &exc)
1116 for (
typename ScratchAndCopyDataList::iterator p =
1117 scratch_and_copy_data_list.begin();
1118 p != scratch_and_copy_data_list.end();
1120 if (p->scratch_data.get() == scratch_data)
1123 p->currently_in_use =
false;
1130 ScratchAndCopyDataObjects<Iterator, ScratchData, CopyData>;
1144 const std::function<void(
const Iterator &, ScratchData &, CopyData &)>
1151 const std::function<void(
const CopyData &)>
copier;
1163 template <
typename Worker,
1166 typename ScratchData,
1169 run(
const std::vector<std::vector<Iterator>> &colored_iterators,
1172 const ScratchData &sample_scratch_data,
1173 const CopyData &sample_copy_data,
1174 const unsigned int chunk_size)
1177 for (
unsigned int color = 0; color < colored_iterators.size(); ++color)
1178 if (colored_iterators[color].
size() > 0)
1181 WorkerAndCopier<Iterator, ScratchData, CopyData>;
1185 sample_scratch_data,
1189 colored_iterators[color].
begin(),
1190 colored_iterators[color].
end(),
1191 [&worker_and_copier](
1192 const tbb::blocked_range<
1193 typename std::vector<Iterator>::const_iterator> &range) {
1194 worker_and_copier(range);
1205# ifdef DEAL_II_WITH_TASKFLOW
1211 namespace taskflow_colored
1218 template <
typename Iterator,
typename ScratchData,
typename CopyData>
1226 const std::function<
void(
const Iterator &, ScratchData &, CopyData &)>
1228 const std::function<
void(
const CopyData &)> &
copier,
1255 ScratchData *scratch_data =
nullptr;
1256 CopyData *copy_data =
nullptr;
1262 for (
typename ScratchAndCopyDataList::iterator p =
1263 scratch_and_copy_data_list.begin();
1264 p != scratch_and_copy_data_list.end();
1266 if (p->currently_in_use ==
false)
1268 scratch_data = p->scratch_data.get();
1269 copy_data = p->copy_data.get();
1270 p->currently_in_use =
true;
1276 if (scratch_data ==
nullptr)
1280 scratch_and_copy_data_list.emplace_back(
1285 scratch_and_copy_data_list.back().scratch_data.get();
1286 copy_data = scratch_and_copy_data_list.back().copy_data.get();
1295 for (
const auto &it : range)
1298 worker(it, *scratch_data, *copy_data);
1303 catch (
const std::exception &exc)
1320 for (
typename ScratchAndCopyDataList::iterator p =
1321 scratch_and_copy_data_list.begin();
1322 p != scratch_and_copy_data_list.end();
1324 if (p->scratch_data.get() == scratch_data)
1327 p->currently_in_use =
false;
1334 ScratchAndCopyDataObjects<Iterator, ScratchData, CopyData>;
1348 const std::function<void(
const Iterator &, ScratchData &, CopyData &)>
1355 const std::function<void(
const CopyData &)>
copier;
1367 template <
typename Worker,
1370 typename ScratchData,
1373 run(
const std::vector<std::vector<Iterator>> &colored_iterators,
1374 const Worker &worker,
1375 const Copier &copier,
1376 const ScratchData &sample_scratch_data,
1377 const CopyData &sample_copy_data,
1378 const unsigned int chunk_size)
1381 WorkerAndCopier<Iterator, ScratchData, CopyData>;
1385 sample_scratch_data,
1389 tf::Taskflow taskflow;
1392 for (
auto &color : colored_iterators)
1393 if (color.size() > 0)
1395 const tf::IndexRange<int> range(0, color.size(), 1);
1396 auto task = taskflow.for_each_by_index(
1399 &worker_and_copier](
const tf::IndexRange<int> &subrange) {
1401 &color[subrange.begin()], subrange.size());
1402 worker_and_copier(chunk);
1404 tf::GuidedPartitioner(chunk_size));
1406 if (!last_task.empty())
1407 last_task.precede(task);
1415 if (executor.this_worker_id() != -1)
1416 executor.corun(taskflow);
1418 executor.run(taskflow).wait();
1476 template <
typename Worker,
1479 typename ScratchData,
1482 run(
const std::vector<std::vector<Iterator>> &colored_iterators,
1485 const ScratchData &sample_scratch_data,
1486 const CopyData &sample_copy_data,
1488 const unsigned int chunk_size = 8);
1540 template <
typename Worker,
1543 typename ScratchData,
1550 const ScratchData &sample_scratch_data,
1551 const CopyData &sample_copy_data,
1553 const unsigned int chunk_size = 8)
1556 ExcMessage(
"The queue length must be at least one, and preferably "
1557 "larger than the number of processors on this system."));
1559 Assert(chunk_size > 0,
ExcMessage(
"The chunk_size must be at least one."));
1569# if defined(DEAL_II_WITH_TBB) || defined(DEAL_II_WITH_TASKFLOW)
1570 if (
static_cast<const std::function<
void(
const CopyData &)
> &>(copier))
1573# if defined(DEAL_II_WITH_TASKFLOW)
1578 sample_scratch_data,
1582# elif defined(DEAL_II_WITH_TBB)
1587 sample_scratch_data,
1609 std::vector<std::vector<Iterator>> all_iterators(1);
1610 for (Iterator p =
begin; p !=
end; ++p)
1616 sample_scratch_data,
1629 begin,
end, worker, copier, sample_scratch_data, sample_copy_data);
1644 typename IteratorRangeType,
1645 typename ScratchData,
1647 typename = std::enable_if_t<
1648 has_begin_and_end<IteratorRangeType> &&
1649 !std::is_same_v<IteratorRangeType,
1652 run(IteratorRangeType iterator_range,
1655 const ScratchData &sample_scratch_data,
1656 const CopyData &sample_copy_data,
1658 const unsigned int chunk_size = 8)
1661 run(iterator_range.begin(),
1662 iterator_range.end(),
1665 sample_scratch_data,
1676 template <
typename Worker,
1679 typename ScratchData,
1685 const ScratchData &sample_scratch_data,
1686 const CopyData &sample_copy_data,
1688 const unsigned int chunk_size = 8)
1692 iterator_range.
end(),
1695 sample_scratch_data,
1703 template <
typename Worker,
1706 typename ScratchData,
1709 run(
const std::vector<std::vector<Iterator>> &colored_iterators,
1712 const ScratchData &sample_scratch_data,
1713 const CopyData &sample_copy_data,
1714 const unsigned int queue_length,
1715 const unsigned int chunk_size)
1718 ExcMessage(
"The queue length must be at least one, and preferably "
1719 "larger than the number of processors on this system."));
1721 Assert(chunk_size > 0,
ExcMessage(
"The chunk_size must be at least one."));
1727# ifdef DEAL_II_WITH_TASKFLOW
1731 sample_scratch_data,
1737# elif defined(DEAL_II_WITH_TBB)
1741 sample_scratch_data,
1755 sample_scratch_data,
1803 template <
typename MainClass,
1805 typename ScratchData,
1810 MainClass &main_object,
1811 void (MainClass::*worker)(const Iterator &, ScratchData &, CopyData &),
1812 void (MainClass::*copier)(const CopyData &),
1813 const ScratchData &sample_scratch_data,
1814 const CopyData &sample_copy_data,
1816 const unsigned
int chunk_size = 8)
1822 [&main_object, worker](
const Iterator &
iterator,
1823 ScratchData &scratch_data,
1824 CopyData ©_data) {
1825 (main_object.*worker)(
iterator, scratch_data, copy_data);
1827 [&main_object, copier](
const CopyData ©_data) {
1828 (main_object.*copier)(copy_data);
1830 sample_scratch_data,
1837 template <
typename MainClass,
1839 typename ScratchData,
1844 MainClass &main_object,
1845 void (MainClass::*worker)(const Iterator &, ScratchData &, CopyData &),
1846 void (MainClass::*copier)(const CopyData &),
1847 const ScratchData &sample_scratch_data,
1848 const CopyData &sample_copy_data,
1850 const unsigned
int chunk_size = 8)
1856 [&main_object, worker](
const Iterator &
iterator,
1857 ScratchData &scratch_data,
1858 CopyData ©_data) {
1859 (main_object.*worker)(
iterator, scratch_data, copy_data);
1861 [&main_object, copier](
const CopyData ©_data) {
1862 (main_object.*copier)(copy_data);
1864 sample_scratch_data,
1881 typename IteratorRangeType,
1882 typename ScratchData,
1884 typename = std::enable_if_t<
1885 has_begin_and_end<IteratorRangeType> &&
1886 !std::is_same_v<IteratorRangeType,
1890 IteratorRangeType iterator_range,
1891 MainClass &main_object,
1892 void (MainClass::*worker)(
1896 void (MainClass::*copier)(const CopyData &),
1897 const ScratchData &sample_scratch_data,
1898 const CopyData &sample_copy_data,
1900 const unsigned
int chunk_size = 8)
1903 run(std::begin(iterator_range),
1904 std::end(iterator_range),
1908 sample_scratch_data,
1919 template <
typename MainClass,
1921 typename ScratchData,
1925 MainClass &main_object,
1926 void (MainClass::*worker)(const Iterator &, ScratchData &, CopyData &),
1927 void (MainClass::*copier)(const CopyData &),
1928 const ScratchData &sample_scratch_data,
1929 const CopyData &sample_copy_data,
1931 const unsigned
int chunk_size = 8)
1934 run(std::begin(iterator_range),
1935 std::end(iterator_range),
1939 sample_scratch_data,
***mech_lbc_system increment_interpolation_handlers push_back(scale_z_handler)
IteratorOverIterators end() const
IteratorOverIterators begin()
static unsigned int n_threads()
static tf::Executor & get_taskflow_executor()
A class that provides a separate storage location on each thread that accesses the object.
typename internal::ScratchAndCopyDataObjects< Iterator, ScratchData, CopyData > ScratchAndCopyDataObjects
const CopyData & sample_copy_data
Threads::ThreadLocalStorage< ScratchAndCopyDataList > data
std::list< ScratchAndCopyDataObjects > ScratchAndCopyDataList
void operator()(const ArrayView< const Iterator > &range)
const std::function< void(const Iterator &, ScratchData &, CopyData &)> worker
const ScratchData & sample_scratch_data
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)
const std::function< void(const CopyData &)> copier
std::list< ScratchAndCopyDataObjects > ScratchAndCopyDataList
typename internal::ScratchAndCopyDataObjects< Iterator, ScratchData, CopyData > ScratchAndCopyDataObjects
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)
Threads::ThreadLocalStorage< ScratchAndCopyDataList > data
void operator()(const tbb::blocked_range< typename std::vector< Iterator >::const_iterator > &range)
const std::function< void(const Iterator &, ScratchData &, CopyData &)> worker
const CopyData & sample_copy_data
const ScratchData & sample_scratch_data
const std::function< void(const CopyData &)> copier
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)
Threads::ThreadLocalStorage< typename ItemType::ScratchDataList > thread_local_scratch
std::vector< ItemType > item_buffer
const unsigned int chunk_size
std::pair< Iterator, Iterator > remaining_iterator_range
const ScratchData & sample_scratch_data
#define DEAL_II_NAMESPACE_OPEN
#define DEAL_II_TBB_WITH_ONEAPI
#define DEAL_II_NAMESPACE_CLOSE
#define Assert(cond, exc)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcMessage(std::string arg1)
void handle_unknown_exception()
void handle_std_exception(const std::exception &exc)
void run(const Iterator &begin, const std_cxx20::type_identity_t< Iterator > &end, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data)
void run(const std::vector< std::vector< Iterator > > &colored_iterators, const Worker &worker, const Copier &copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const unsigned int chunk_size)
void run(const Iterator &begin, const std_cxx20::type_identity_t< Iterator > &end, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const unsigned int=2 *MultithreadInfo::n_threads(), const unsigned int chunk_size=8)
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)
void run(const Iterator &begin, const std_cxx20::type_identity_t< Iterator > &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)
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)
void parallel_for(Iterator x_begin, Iterator x_end, const Functor &functor, const unsigned int grainsize)
typename type_identity< T >::type type_identity_t
std::unique_ptr< ScratchData > scratch_data
ScratchAndCopyDataObjects()
std::unique_ptr< CopyData > copy_data
ScratchAndCopyDataObjects(const ScratchAndCopyDataObjects &)
ScratchAndCopyDataObjects(std::unique_ptr< ScratchData > &&p, std::unique_ptr< CopyData > &&q, const bool in_use)
ScratchDataObject(std::unique_ptr< ScratchData > &&p, const bool in_use)
ScratchDataObject(ScratchDataObject &&o) noexcept=default
ScratchDataObject(ScratchData *p, const bool in_use)
ScratchDataObject(const ScratchDataObject &)
std::unique_ptr< ScratchData > scratch_data
std::list< ScratchDataObject< ScratchData > > ScratchDataList
const ScratchData * sample_scratch_data
std::vector< Iterator > iterators
std::vector< CopyData > copy_datas
Threads::ThreadLocalStorage< ScratchDataList > * scratch_data