124template <
typename C = DefaultClosureWrapper>
180 template <
typename F>
186 template <
typename F>
187 TF_FORCE_INLINE
decltype(
auto)
operator () (F&& callable) {
189 return std::forward<F>(callable);
193 return [
this, c=std::forward<F>(callable)]()
mutable { _closure_wrapper(c); };
202 size_t _chunk_size{0};
261template <
typename C = DefaultClosureWrapper>
296 return this->_chunk_size ? this->_chunk_size : N/W + (w < N%W);
306 template <
typename F>
308 size_t N,
size_t W,
size_t curr_b,
size_t chunk_size, F&& func
312 size_t curr_e = (std::min)(curr_b +
chunk_size, N);
313 if constexpr (std::is_same_v<std::invoke_result_t<F, size_t, size_t>,
bool>) {
314 if(func(curr_b, curr_e)) {
318 func(curr_b, curr_e);
340 template <IndexRangesLike R,
typename F>
341 void loop(
const R& range,
size_t N,
size_t W,
size_t curr_b,
size_t chunk_size, F&& func)
const {
344 size_t curr_e = (std::min)(curr_b +
chunk_size, N);
345 if constexpr (R::rank == 1) {
346 if constexpr (std::is_same_v<std::invoke_result_t<F, R>,
bool>) {
347 if(func(range.unravel(curr_b, curr_e))) {
351 func(range.unravel(curr_b, curr_e));
355 while(curr_b < curr_e) {
356 auto box = range.lower_slice(curr_b, curr_e - curr_b);
357 if constexpr (std::is_same_v<std::invoke_result_t<F, R>,
bool>) {
364 curr_b += box.size();
416template <
typename C = DefaultClosureWrapper>
451 template <
typename F>
453 size_t N,
size_t W, std::atomic<size_t>& next, F&& func
456 size_t chunk_size = (this->_chunk_size == 0) ?
size_t{1} : this->_chunk_size;
459 float p2 = 0.5f /
static_cast<float>(W);
460 size_t curr_b = next.load(std::memory_order_relaxed);
464 size_t r = N - curr_b;
469 curr_b = next.fetch_add(
chunk_size, std::memory_order_relaxed);
473 if constexpr (std::is_same_v<std::invoke_result_t<F, size_t, size_t>,
bool>) {
474 if(func(curr_b, (std::min)(curr_b +
chunk_size, N))) {
478 func(curr_b, (std::min)(curr_b +
chunk_size, N));
485 size_t q =
static_cast<size_t>(p2 * r);
489 size_t curr_e = (std::min)(curr_b + q, N);
490 if(next.compare_exchange_strong(curr_b, curr_e, std::memory_order_relaxed,
491 std::memory_order_relaxed)) {
492 if constexpr (std::is_same_v<std::invoke_result_t<F, size_t, size_t>,
bool>) {
493 if(func(curr_b, curr_e)) {
497 func(curr_b, curr_e);
508 template <IndexRangesLike R,
typename F>
509 void loop(
const R& range,
size_t N,
size_t W, std::atomic<size_t>& next, F&& func)
const {
511 size_t chunk_size = (this->_chunk_size == 0) ?
size_t{1} : this->_chunk_size;
513 float p2 = 0.5f /
static_cast<float>(W);
514 size_t curr_b = next.load(std::memory_order_relaxed);
517 size_t r = N - curr_b;
518 size_t csize = (r < p1) ? chunk_size : (std::max)(static_cast<size_t>(p2 * r),
chunk_size);
519 if constexpr (R::rank == 1) {
520 size_t curr_e = (std::min)(curr_b + csize, N);
521 if(next.compare_exchange_weak(curr_b, curr_e,
522 std::memory_order_relaxed,
523 std::memory_order_relaxed)) {
524 if constexpr (std::is_same_v<std::invoke_result_t<F, R>,
bool>) {
525 if(func(range.unravel(curr_b, curr_e))) {
529 func(range.unravel(curr_b, curr_e));
534 auto box = range.upper_slice(curr_b, csize);
535 if(next.compare_exchange_weak(curr_b, curr_b + box.size(),
536 std::memory_order_relaxed,
537 std::memory_order_relaxed)) {
538 if constexpr (std::is_same_v<std::invoke_result_t<F, R>,
bool>) {
545 curr_b += box.size();
596template <
typename C = DefaultClosureWrapper>
630 template <
typename F>
632 size_t N,
size_t, std::atomic<size_t>& next, F&& func
635 size_t chunk_size = (this->_chunk_size == 0) ?
size_t{1} : this->_chunk_size;
636 size_t curr_b = next.fetch_add(
chunk_size, std::memory_order_relaxed);
639 if constexpr (std::is_same_v<std::invoke_result_t<F, size_t, size_t>,
bool>) {
640 if(func(curr_b, (std::min)(curr_b +
chunk_size, N))) {
644 func(curr_b, (std::min)(curr_b +
chunk_size, N));
646 curr_b = next.fetch_add(
chunk_size, std::memory_order_relaxed);
653 template <IndexRangesLike R,
typename F>
654 void loop(
const R& range,
size_t N,
size_t, std::atomic<size_t>& next, F&& func)
const {
655 size_t curr_b = next.load(std::memory_order_relaxed);
656 size_t chunk_size = (this->_chunk_size == 0) ?
size_t{1} : this->_chunk_size;
659 if constexpr (R::rank == 1) {
660 size_t curr_e = (std::min)(curr_b +
chunk_size, N);
661 if(next.compare_exchange_weak(curr_b, curr_e,
662 std::memory_order_relaxed,
663 std::memory_order_relaxed)) {
664 if constexpr (std::is_same_v<std::invoke_result_t<F, R>,
bool>) {
665 if(func(range.unravel(curr_b, curr_e))) {
669 func(range.unravel(curr_b, curr_e));
674 auto box = range.upper_slice(curr_b,
chunk_size);
675 if(next.compare_exchange_weak(curr_b, curr_b + box.size(),
676 std::memory_order_relaxed,
677 std::memory_order_relaxed)) {
678 if constexpr (std::is_same_v<std::invoke_result_t<F, R>,
bool>) {
685 curr_b += box.size();
736template <
typename C = DefaultClosureWrapper>
779 float alpha()
const {
return _alpha; }
784 float beta()
const {
return _beta; }
794 size_t b1 =
static_cast<size_t>(_alpha * N * W);
795 size_t b2 =
static_cast<size_t>(_beta * N * W);
801 b1 = (std::max)(b1,
size_t{1});
802 b2 = (std::max)(b2, b1 + 1);
814 template <
typename F>
816 size_t N,
size_t W, std::atomic<size_t>& next, F&& func
821 std::default_random_engine engine {std::random_device{}()};
822 std::uniform_int_distribution<size_t> dist(b1, b2);
825 size_t curr_b = next.fetch_add(
chunk_size, std::memory_order_relaxed);
828 if constexpr (std::is_same_v<std::invoke_result_t<F, size_t, size_t>,
bool>) {
829 if(func(curr_b, (std::min)(curr_b +
chunk_size, N))) {
833 func(curr_b, (std::min)(curr_b +
chunk_size, N));
836 curr_b = next.fetch_add(
chunk_size, std::memory_order_relaxed);
843 template <IndexRangesLike R,
typename F>
844 void loop(
const R& range,
size_t N,
size_t W, std::atomic<size_t>& next, F&& func)
const {
848 std::default_random_engine engine{std::random_device{}()};
849 std::uniform_int_distribution<size_t> dist(b1, b2);
851 size_t curr_b = next.load(std::memory_order_relaxed);
854 if constexpr (R::rank == 1) {
855 size_t curr_e = (std::min)(curr_b + dist(engine), N);
856 if(next.compare_exchange_weak(curr_b, curr_e,
857 std::memory_order_relaxed,
858 std::memory_order_relaxed)) {
859 if constexpr (std::is_same_v<std::invoke_result_t<F, R>,
bool>) {
860 if(func(range.unravel(curr_b, curr_e))) {
864 func(range.unravel(curr_b, curr_e));
869 auto box = range.upper_slice(curr_b, dist(engine));
870 if(next.compare_exchange_weak(curr_b, curr_b + box.size(),
871 std::memory_order_relaxed,
872 std::memory_order_relaxed)) {
873 if constexpr (std::is_same_v<std::invoke_result_t<F, R>,
bool>) {
880 curr_b += box.size();
888 float _alpha {0.01f};
906concept PartitionerLike = std::derived_from<P, PartitionerBase<typename P::closure_wrapper_type>>;
class to create a default closure wrapper
Definition partitioner.hpp:51
DynamicPartitioner()=default
default constructor
DynamicPartitioner(size_t sz, C &&closure)
construct a dynamic partitioner with the given chunk size and the closure
Definition partitioner.hpp:619
static constexpr PartitionerType type()
queries the partition type (dynamic)
Definition partitioner.hpp:604
DynamicPartitioner(size_t sz)
construct a dynamic partitioner with the given chunk size
Definition partitioner.hpp:614
class to create a guided partitioner for scheduling parallel algorithms
Definition partitioner.hpp:417
GuidedPartitioner(size_t sz, C &&closure)
construct a guided partitioner with the given chunk size and the closure
Definition partitioner.hpp:440
GuidedPartitioner(size_t sz)
construct a guided partitioner with the given chunk size
Definition partitioner.hpp:435
GuidedPartitioner()=default
default constructor
static constexpr PartitionerType type()
queries the partition type (dynamic)
Definition partitioner.hpp:424
PartitionerBase(size_t chunk_size)
construct a partitioner with the given chunk size
Definition partitioner.hpp:147
static constexpr bool is_default_wrapper_v
indicating if the given closure wrapper is a default wrapper (i.e., empty)
Definition partitioner.hpp:132
C closure_wrapper_type
the closure type
Definition partitioner.hpp:137
void chunk_size(size_t cz)
update the chunk size of this partitioner
Definition partitioner.hpp:165
const C & closure_wrapper() const
acquire an immutable access to the closure wrapper object
Definition partitioner.hpp:170
void closure_wrapper(F &&fn)
modify the closure wrapper object
Definition partitioner.hpp:181
PartitionerBase(size_t chunk_size, C &&closure_wrapper)
construct a partitioner with the given chunk size and closure wrapper
Definition partitioner.hpp:152
C & closure_wrapper()
acquire a mutable access to the closure wrapper object
Definition partitioner.hpp:175
PartitionerBase()=default
default constructor
size_t chunk_size() const
query the chunk size of this partitioner
Definition partitioner.hpp:160
RandomPartitioner(size_t sz, C &&closure)
construct a random partitioner with the given chunk size and the closure
Definition partitioner.hpp:759
RandomPartitioner(float alpha, float beta, C &&closure)
constructs a random partitioner with the given parameters and the closure
Definition partitioner.hpp:771
std::pair< size_t, size_t > chunk_size_range(size_t N, size_t W) const
queries the range of chunk size
Definition partitioner.hpp:792
RandomPartitioner(float alpha, float beta)
constructs a random partitioner with the given parameters
Definition partitioner.hpp:766
RandomPartitioner()=default
default constructor
static constexpr PartitionerType type()
queries the partition type (dynamic)
Definition partitioner.hpp:744
float alpha() const
queries the alpha value
Definition partitioner.hpp:779
RandomPartitioner(size_t sz)
construct a dynamic partitioner with the given chunk size
Definition partitioner.hpp:754
float beta() const
queries the beta value
Definition partitioner.hpp:784
StaticPartitioner()=default
default constructor
size_t adjusted_chunk_size(size_t N, size_t W, size_t w) const
queries the adjusted chunk size
Definition partitioner.hpp:295
StaticPartitioner(size_t sz)
construct a static partitioner with the given chunk size
Definition partitioner.hpp:279
StaticPartitioner(size_t sz, C &&closure)
construct a static partitioner with the given chunk size and the closure
Definition partitioner.hpp:284
static constexpr PartitionerType type()
queries the partition type (static)
Definition partitioner.hpp:269
determines if a type is a partitioner
Definition partitioner.hpp:906
taskflow namespace
Definition small_vector.hpp:20
@ STATIC
static task type
Definition task.hpp:25
PartitionerType
enumeration of all partitioner types
Definition partitioner.hpp:19
@ DYNAMIC
dynamic partitioner type
Definition partitioner.hpp:23
@ STATIC
static partitioner type
Definition partitioner.hpp:21
constexpr bool is_partitioner_v
determines if a type is a partitioner (variable template)
Definition partitioner.hpp:916
GuidedPartitioner<> DefaultPartitioner
default partitioner set to tf::GuidedPartitioner
Definition partitioner.hpp:898