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 func(curr_b, curr_e);
321 template <
typename F>
323 size_t N,
size_t W,
size_t curr_b,
size_t chunk_size, F&& func
327 size_t curr_e = (std::min)(curr_b +
chunk_size, N);
328 if(func(curr_b, curr_e)) {
338 template <IndexRangeMDLike R,
typename F>
339 void loop(R& range,
size_t N,
size_t W, std::atomic<size_t>& next, F&& func)
const {
341 size_t curr_b = next.load(std::memory_order_relaxed);
342 size_t chunk_size = (this->_chunk_size == 0) ? (N+W-1) / W : this->_chunk_size;
346 auto [box, consumed] = range.consume_chunk(curr_b,
chunk_size);
347 if (next.compare_exchange_weak(curr_b, curr_b + consumed,
348 std::memory_order_relaxed,
349 std::memory_order_relaxed)) {
401template <
typename C = DefaultClosureWrapper>
436 template <
typename F>
438 size_t N,
size_t W, std::atomic<size_t>& next, F&& func
441 size_t chunk_size = (this->_chunk_size == 0) ?
size_t{1} : this->_chunk_size;
444 float p2 = 0.5f /
static_cast<float>(W);
445 size_t curr_b = next.load(std::memory_order_relaxed);
449 size_t r = N - curr_b;
454 curr_b = next.fetch_add(
chunk_size, std::memory_order_relaxed);
458 func(curr_b, (std::min)(curr_b +
chunk_size, N));
464 size_t q =
static_cast<size_t>(p2 * r);
469 size_t curr_e = (std::min)(curr_b + q, N);
470 if(next.compare_exchange_strong(curr_b, curr_e, std::memory_order_relaxed,
471 std::memory_order_relaxed)) {
472 func(curr_b, curr_e);
483 template <
typename F>
485 size_t N,
size_t W, std::atomic<size_t>& next, F&& func
488 size_t chunk_size = (this->_chunk_size == 0) ?
size_t{1} : this->_chunk_size;
491 float p2 = 0.5f /
static_cast<float>(W);
492 size_t curr_b = next.load(std::memory_order_relaxed);
496 size_t r = N - curr_b;
501 curr_b = next.fetch_add(
chunk_size, std::memory_order_relaxed);
505 if(func(curr_b, (std::min)(curr_b +
chunk_size, N))) {
513 size_t q =
static_cast<size_t>(p2 * r);
518 size_t curr_e = (std::min)(curr_b + q, N);
519 if(next.compare_exchange_strong(curr_b, curr_e, std::memory_order_relaxed,
520 std::memory_order_relaxed)) {
521 if(func(curr_b, curr_e)) {
534 template <IndexRangeMDLike R,
typename F>
535 void loop(R& range,
size_t N,
size_t W, std::atomic<size_t>& next, F&& func)
const {
537 size_t chunk_size = (this->_chunk_size == 0) ?
size_t{1} : this->_chunk_size;
538 size_t requested_chunk_size;
540 float p2 = 0.5f /
static_cast<float>(W);
541 size_t curr_b = next.load(std::memory_order_relaxed);
545 size_t r = N - curr_b;
553 requested_chunk_size = (std::max)(
static_cast<size_t>(p2*r),
chunk_size);
556 auto [box, consumed] = range.consume_chunk(curr_b, requested_chunk_size);
558 if (next.compare_exchange_weak(curr_b, curr_b + consumed,
559 std::memory_order_relaxed,
560 std::memory_order_relaxed)) {
612template <
typename C = DefaultClosureWrapper>
646 template <
typename F>
648 size_t N,
size_t, std::atomic<size_t>& next, F&& func
651 size_t chunk_size = (this->_chunk_size == 0) ?
size_t{1} : this->_chunk_size;
652 size_t curr_b = next.fetch_add(
chunk_size, std::memory_order_relaxed);
655 func(curr_b, (std::min)(curr_b +
chunk_size, N));
656 curr_b = next.fetch_add(
chunk_size, std::memory_order_relaxed);
663 template <
typename F>
665 size_t N,
size_t, std::atomic<size_t>& next, F&& func
668 size_t chunk_size = (this->_chunk_size == 0) ?
size_t{1} : this->_chunk_size;
669 size_t curr_b = next.fetch_add(
chunk_size, std::memory_order_relaxed);
672 if(func(curr_b, (std::min)(curr_b +
chunk_size, N))) {
675 curr_b = next.fetch_add(
chunk_size, std::memory_order_relaxed);
682 template <IndexRangeMDLike R,
typename F>
683 void loop(R& range,
size_t N,
size_t, std::atomic<size_t>& next, F&& func)
const {
685 size_t curr_b = next.load(std::memory_order_relaxed);
686 size_t chunk_size = (this->_chunk_size == 0) ?
size_t{1} : this->_chunk_size;
690 auto [box, consumed] = range.consume_chunk(curr_b,
chunk_size);
691 if (next.compare_exchange_weak(curr_b, curr_b + consumed,
692 std::memory_order_relaxed,
693 std::memory_order_relaxed)) {
745template <
typename C = DefaultClosureWrapper>
788 float alpha()
const {
return _alpha; }
793 float beta()
const {
return _beta; }
803 size_t b1 =
static_cast<size_t>(_alpha * N * W);
804 size_t b2 =
static_cast<size_t>(_beta * N * W);
810 b1 = (std::max)(b1,
size_t{1});
811 b2 = (std::max)(b2, b1 + 1);
823 template <
typename F>
825 size_t N,
size_t W, std::atomic<size_t>& next, F&& func
830 std::default_random_engine engine {std::random_device{}()};
831 std::uniform_int_distribution<size_t> dist(b1, b2);
834 size_t curr_b = next.fetch_add(
chunk_size, std::memory_order_relaxed);
837 func(curr_b, (std::min)(curr_b +
chunk_size, N));
839 curr_b = next.fetch_add(
chunk_size, std::memory_order_relaxed);
846 template <
typename F>
848 size_t N,
size_t W, std::atomic<size_t>& next, F&& func
853 std::default_random_engine engine {std::random_device{}()};
854 std::uniform_int_distribution<size_t> dist(b1, b2);
857 size_t curr_b = next.fetch_add(
chunk_size, std::memory_order_relaxed);
860 if(func(curr_b, (std::min)(curr_b +
chunk_size, N))){
864 curr_b = next.fetch_add(
chunk_size, std::memory_order_relaxed);
871 template <IndexRangeMDLike R,
typename F>
872 void loop(R& range,
size_t N,
size_t W, std::atomic<size_t>& next, F&& func)
const {
876 std::default_random_engine engine{std::random_device{}()};
877 std::uniform_int_distribution<size_t> dist(b1, b2);
879 size_t curr_b = next.load(std::memory_order_relaxed);
882 auto [box, consumed] = range.consume_chunk(curr_b, dist(engine));
883 if (next.compare_exchange_weak(curr_b, curr_b + consumed,
884 std::memory_order_relaxed,
885 std::memory_order_relaxed)) {
895 float _alpha {0.01f};
913concept Partitioner = 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:635
static constexpr PartitionerType type()
queries the partition type (dynamic)
Definition partitioner.hpp:620
DynamicPartitioner(size_t sz)
construct a dynamic partitioner with the given chunk size
Definition partitioner.hpp:630
class to create a guided partitioner for scheduling parallel algorithms
Definition partitioner.hpp:402
GuidedPartitioner(size_t sz, C &&closure)
construct a guided partitioner with the given chunk size and the closure
Definition partitioner.hpp:425
GuidedPartitioner(size_t sz)
construct a guided partitioner with the given chunk size
Definition partitioner.hpp:420
GuidedPartitioner()=default
default constructor
static constexpr PartitionerType type()
queries the partition type (dynamic)
Definition partitioner.hpp:409
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:768
RandomPartitioner(float alpha, float beta, C &&closure)
constructs a random partitioner with the given parameters and the closure
Definition partitioner.hpp:780
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:801
RandomPartitioner(float alpha, float beta)
constructs a random partitioner with the given parameters
Definition partitioner.hpp:775
RandomPartitioner()=default
default constructor
static constexpr PartitionerType type()
queries the partition type (dynamic)
Definition partitioner.hpp:753
float alpha() const
queries the alpha value
Definition partitioner.hpp:788
RandomPartitioner(size_t sz)
construct a dynamic partitioner with the given chunk size
Definition partitioner.hpp:763
float beta() const
queries the beta value
Definition partitioner.hpp:793
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:913
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:923
GuidedPartitioner<> DefaultPartitioner
default partitioner set to tf::GuidedPartitioner
Definition partitioner.hpp:905