diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 4a762f7e15..2abe94656d 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -219,6 +219,9 @@ add_library(libslic3r STATIC SimplifyMeshImpl.hpp SimplifyMesh.cpp MarchingSquares.hpp + Execution/Execution.hpp + Execution/ExecutionSeq.hpp + Execution/ExecutionTBB.hpp Optimize/Optimizer.hpp Optimize/NLoptOptimizer.hpp Optimize/BruteforceOptimizer.hpp diff --git a/src/libslic3r/Execution/Execution.hpp b/src/libslic3r/Execution/Execution.hpp new file mode 100644 index 0000000000..809cc45d3c --- /dev/null +++ b/src/libslic3r/Execution/Execution.hpp @@ -0,0 +1,100 @@ +#ifndef EXECUTION_HPP +#define EXECUTION_HPP + +#include +#include +#include +#include + +#include "libslic3r/libslic3r.h" + +namespace Slic3r { + +template +using remove_cvref_t = std::remove_reference_t>; + +// Override for valid execution policies +template struct IsExecutionPolicy_ : public std::false_type {}; + +template constexpr bool IsExecutionPolicy = + IsExecutionPolicy_>::value; + +template +using ExecutionPolicyOnly = std::enable_if_t, T>; + +namespace execution { + +// This struct needs to be specialized for each execution policy. +// See ExecutionSeq.hpp and ExecutionTBB.hpp for example. +template struct Traits {}; + +template using AsTraits = Traits>; + +// Each execution policy should declare two types of mutexes. A a spin lock and +// a blocking mutex. +template using SpinningMutex = typename Traits::SpinningMutex; +template using BlockingMutex = typename Traits::BlockingMutex; + +// Query the available threads for concurrency. +template > +size_t max_concurrency(const EP &ep) +{ + return AsTraits::max_concurrency(ep); +} + +// foreach loop with the execution policy passed as argument. Granularity can +// be specified explicitly. max_concurrency() can be used for optimal results. +template> +void for_each(const EP &ep, It from, It to, Fn &&fn, size_t granularity = 1) +{ + AsTraits::for_each(ep, from, to, std::forward(fn), granularity); +} + +// A reduce operation with the execution policy passed as argument. +// mergefn has T(const T&, const T&) signature +// accessfn has T(I) signature if I is an integral type and +// T(const I::value_type &) if I is an iterator type. +template > +T reduce(const EP & ep, + I from, + I to, + const T & init, + MergeFn && mergefn, + AccessFn &&accessfn, + size_t granularity = 1) +{ + return AsTraits::reduce(ep, from, to, init, + std::forward(mergefn), + std::forward(accessfn), + granularity); +} + +// An overload of reduce method to be used with iterators as 'from' and 'to' +// arguments. +template, + class = IteratorOnly > +T reduce(const EP &ep, + I from, + I to, + const T & init, + MergeFn &&mergefn, + size_t granularity = 1) +{ + return reduce( + ep, from, to, init, std::forward(mergefn), + [](typename I::value_type &i) { return i; }, granularity); +} + +} // namespace execution_policy +} // namespace Slic3r + +#endif // EXECUTION_HPP diff --git a/src/libslic3r/Execution/ExecutionSeq.hpp b/src/libslic3r/Execution/ExecutionSeq.hpp new file mode 100644 index 0000000000..321d65631b --- /dev/null +++ b/src/libslic3r/Execution/ExecutionSeq.hpp @@ -0,0 +1,84 @@ +#ifndef EXECUTIONSEQ_HPP +#define EXECUTIONSEQ_HPP + +#ifdef PRUSASLICER_USE_EXECUTION_STD // Conflicts with our version of TBB +#include +#endif + +#include "Execution.hpp" + +namespace Slic3r { + +// Execution policy implementing dummy sequential algorithms +struct ExecutionSeq {}; + +template<> struct IsExecutionPolicy_ : public std::true_type {}; + +static constexpr ExecutionSeq ex_seq = {}; + +template struct IsSequentialEP_ { static constexpr bool value = false; }; + +template<> struct IsSequentialEP_: public std::true_type {}; +#ifdef PRUSASLICER_USE_EXECUTION_STD +template<> struct IsExecutionPolicy_: public std::true_type {}; +template<> struct IsSequentialEP_: public std::true_type {}; +#endif + +template +constexpr bool IsSequentialEP = IsSequentialEP_>::value; + +template +using SequentialEPOnly = std::enable_if_t, R>; + +template +struct execution::Traits> { +private: + struct _Mtx { inline void lock() {} inline void unlock() {} }; + + template + static IteratorOnly loop_(It from, It to, Fn &&fn) + { + for (auto it = from; it != to; ++it) fn(*it); + } + + template + static IntegerOnly loop_(I from, I to, Fn &&fn) + { + for (I i = from; i < to; ++i) fn(i); + } + +public: + using SpinningMutex = _Mtx; + using BlockingMutex = _Mtx; + + template + static void for_each(const EP &, + It from, + It to, + Fn &&fn, + size_t /* ignore granularity */ = 1) + { + loop_(from, to, std::forward(fn)); + } + + template + static T reduce(const EP &, + I from, + I to, + const T & init, + MergeFn &&mergefn, + AccessFn &&access, + size_t /*granularity*/ = 1 + ) + { + T acc = init; + loop_(from, to, [&](auto &i) { acc = mergefn(acc, access(i)); }); + return acc; + } + + static size_t max_concurrency(const EP &) { return 1; } +}; + +} // namespace Slic3r + +#endif // EXECUTIONSEQ_HPP diff --git a/src/libslic3r/Execution/ExecutionTBB.hpp b/src/libslic3r/Execution/ExecutionTBB.hpp new file mode 100644 index 0000000000..cf6373c466 --- /dev/null +++ b/src/libslic3r/Execution/ExecutionTBB.hpp @@ -0,0 +1,77 @@ +#ifndef EXECUTIONTBB_HPP +#define EXECUTIONTBB_HPP + +#include +#include +#include +#include +#include + +#include "Execution.hpp" + +namespace Slic3r { + +struct ExecutionTBB {}; +template<> struct IsExecutionPolicy_ : public std::true_type {}; + +// Execution policy using Intel TBB library under the hood. +static constexpr ExecutionTBB ex_tbb = {}; + +template<> struct execution::Traits { +private: + + template + static IteratorOnly loop_(const tbb::blocked_range &range, Fn &&fn) + { + for (auto &el : range) fn(el); + } + + template + static IntegerOnly loop_(const tbb::blocked_range &range, Fn &&fn) + { + for (I i = range.begin(); i < range.end(); ++i) fn(i); + } + +public: + using SpinningMutex = tbb::spin_mutex; + using BlockingMutex = tbb::mutex; + + template + static void for_each(const ExecutionTBB &, + It from, It to, Fn &&fn, size_t granularity) + { + tbb::parallel_for(tbb::blocked_range{from, to, granularity}, + [&fn](const auto &range) { + loop_(range, std::forward(fn)); + }); + } + + template + static T reduce(const ExecutionTBB &, + I from, + I to, + const T &init, + MergeFn &&mergefn, + AccessFn &&access, + size_t granularity = 1 + ) + { + return tbb::parallel_reduce( + tbb::blocked_range{from, to, granularity}, init, + [&](const auto &range, T subinit) { + T acc = subinit; + loop_(range, [&](auto &i) { acc = mergefn(acc, access(i)); }); + return acc; + }, + std::forward(mergefn)); + } + + static size_t max_concurrency(const ExecutionTBB &) + { + return tbb::this_task_arena::max_concurrency(); + } +}; + +} + +#endif // EXECUTIONTBB_HPP diff --git a/src/libslic3r/MTUtils.hpp b/src/libslic3r/MTUtils.hpp index 555cfe5019..7b903f66c8 100644 --- a/src/libslic3r/MTUtils.hpp +++ b/src/libslic3r/MTUtils.hpp @@ -106,13 +106,8 @@ template bool all_of(const C &container) }); } -template struct remove_cvref -{ - using type = - typename std::remove_cv::type>::type; -}; - -template using remove_cvref_t = typename remove_cvref::type; +template +using remove_cvref_t = std::remove_reference_t>; /// Exactly like Matlab https://www.mathworks.com/help/matlab/ref/linspace.html template> diff --git a/src/libslic3r/SLA/Concurrency.hpp b/src/libslic3r/SLA/Concurrency.hpp index 8ff0ff809e..7299101b31 100644 --- a/src/libslic3r/SLA/Concurrency.hpp +++ b/src/libslic3r/SLA/Concurrency.hpp @@ -1,16 +1,10 @@ #ifndef SLA_CONCURRENCY_H #define SLA_CONCURRENCY_H -#include -#include -#include -#include -#include +// FIXME: Deprecated -#include -#include - -#include +#include +#include namespace Slic3r { namespace sla { @@ -23,124 +17,48 @@ template struct _ccr {}; template<> struct _ccr { - using SpinningMutex = tbb::spin_mutex; - using BlockingMutex = tbb::mutex; - - template - static IteratorOnly loop_(const tbb::blocked_range &range, Fn &&fn) - { - for (auto &el : range) fn(el); - } - - template - static IntegerOnly loop_(const tbb::blocked_range &range, Fn &&fn) - { - for (I i = range.begin(); i < range.end(); ++i) fn(i); - } + using SpinningMutex = execution::SpinningMutex; + using BlockingMutex = execution::BlockingMutex; template static void for_each(It from, It to, Fn &&fn, size_t granularity = 1) { - tbb::parallel_for(tbb::blocked_range{from, to, granularity}, - [&fn](const auto &range) { - loop_(range, std::forward(fn)); - }); + execution::for_each(ex_tbb, from, to, std::forward(fn), granularity); } - template - static T reduce(I from, - I to, - const T &init, - MergeFn &&mergefn, - AccessFn &&access, - size_t granularity = 1 - ) + template + static auto reduce(Args&&...args) { - return tbb::parallel_reduce( - tbb::blocked_range{from, to, granularity}, init, - [&](const auto &range, T subinit) { - T acc = subinit; - loop_(range, [&](auto &i) { acc = mergefn(acc, access(i)); }); - return acc; - }, - std::forward(mergefn)); - } - - template - static IteratorOnly reduce(I from, - I to, - const T & init, - MergeFn &&mergefn, - size_t granularity = 1) - { - return reduce( - from, to, init, std::forward(mergefn), - [](typename I::value_type &i) { return i; }, granularity); + return execution::reduce(ex_tbb, std::forward(args)...); } static size_t max_concurreny() { - return tbb::this_task_arena::max_concurrency(); + return execution::max_concurrency(ex_tbb); } }; template<> struct _ccr { -private: - struct _Mtx { inline void lock() {} inline void unlock() {} }; - -public: - using SpinningMutex = _Mtx; - using BlockingMutex = _Mtx; - - template - static IteratorOnly loop_(It from, It to, Fn &&fn) - { - for (auto it = from; it != to; ++it) fn(*it); - } - - template - static IntegerOnly loop_(I from, I to, Fn &&fn) - { - for (I i = from; i < to; ++i) fn(i); - } + using SpinningMutex = execution::SpinningMutex; + using BlockingMutex = execution::BlockingMutex; template - static void for_each(It from, - It to, - Fn &&fn, - size_t /* ignore granularity */ = 1) + static void for_each(It from, It to, Fn &&fn, size_t granularity = 1) { - loop_(from, to, std::forward(fn)); + execution::for_each(ex_seq, from, to, std::forward(fn), granularity); } - template - static T reduce(I from, - I to, - const T & init, - MergeFn &&mergefn, - AccessFn &&access, - size_t /*granularity*/ = 1 - ) + template + static auto reduce(Args&&...args) { - T acc = init; - loop_(from, to, [&](auto &i) { acc = mergefn(acc, access(i)); }); - return acc; + return execution::reduce(ex_seq, std::forward(args)...); } - template - static IteratorOnly reduce(I from, - I to, - const T &init, - MergeFn &&mergefn, - size_t /*granularity*/ = 1 - ) + static size_t max_concurreny() { - return reduce(from, to, init, std::forward(mergefn), - [](typename I::value_type &i) { return i; }); + return execution::max_concurrency(ex_seq); } - - static size_t max_concurreny() { return 1; } }; using ccr = _ccr;