Core Type Selector for Task Arena Constraints#
Note
To enable this feature, set the TBB_PREVIEW_TASK_ARENA_CORE_TYPE_SELECTOR macro to 1. When available and enabled, the feature-test macro TBB_HAS_TASK_ARENA_CORE_TYPE_SELECTOR is defined.
Description#
On a system with hybrid CPU cores, it is generally best to allow the OS to schedule threads across
all core types. However, advanced users may occasionally need to constrain the scheduling.
The constraints::set_core_type(core_type_id) API supports only a single core type, which may not allow selecting a suitable subset on processors with more than two core types.
The core type selector addresses this by allowing a callable object (selector) to rank every
available core type. The selector is called once for each core type returned by
tbb::info::core_types(). Positive scores indicate core types that should be used, negative
scores exclude core types, and a score of zero means “use only if multi-core-type constraints are
not supported” (see Selector Requirements for details).
This feature extends the tbb::task_arena and the tbb::info specifications with the following API:
Adds the
selectableconstant totask_arena.Adds a new
task_arenaconstructor template that accepts aconstraintsobject together with a selector.Adds a new
task_arena::initializetemplate that accepts aconstraintsobject together with a selector.Adds a new
info::default_concurrencytemplate that returns the effective concurrency for given constraints and selector.
API#
Header#
#define TBB_PREVIEW_TASK_ARENA_CORE_TYPE_SELECTOR 1
#include <oneapi/tbb/task_arena.h>
#include <oneapi/tbb/info.h>
Synopsis#
namespace oneapi {
namespace tbb {
class task_arena {
public:
static constexpr int selectable = /* unspecified */;
template <typename Selector>
task_arena(constraints a_constraints, Selector a_selector,
unsigned reserved_slots = 1,
priority a_priority = priority::normal);
template <typename Selector>
void initialize(constraints a_constraints, Selector a_selector,
unsigned reserved_slots = 1,
priority a_priority = priority::normal);
}; // class task_arena
namespace info {
template <typename Selector>
int default_concurrency(task_arena::constraints c, Selector a_selector);
} // namespace info
} // namespace tbb
} // namespace oneapi
Member Constants#
-
static constexpr int task_arena::selectable#
A special value for constraints::core_type that indicates the core type(s) should be
determined by the selector provided to the constructor or initialize.
Member Functions#
-
template<typename Selector>
task_arena::task_arena(constraints a_constraints, Selector a_selector, unsigned reserved_slots = 1, priority a_priority = priority::normal)#
Requirements: Selector must be a callable type whose call operator accepts a
std::tuple<tbb::core_type_id, std::size_t, std::size_t> and returns a value convertible to int.
See Selector Requirements for the full contract.
Constructs a task_arena whose core type constraint is resolved by calling a_selector
on every available core type. The a_constraints.core_type field should be set to
task_arena::selectable; other constraint fields (numa_id, max_concurrency,
max_threads_per_core) are applied as usual.
If a_constraints.core_type is not selectable, the selector is ignored and the
constructor behaves identically to the existing constraints-based constructor.
-
template<typename Selector>
void task_arena::initialize(constraints a_constraints, Selector a_selector, unsigned reserved_slots = 1, priority a_priority = priority::normal)#
Overrides the arena settings and forces initialization. Core type resolution follows the same rules as the constructor above.
Functions#
-
template<typename Selector>
int info::default_concurrency(task_arena::constraints c, Selector a_selector)#
Requirements: Selector must be a callable type whose call operator accepts a
std::tuple<tbb::core_type_id, std::size_t, std::size_t> and returns a value convertible to int.
See Selector Requirements for the full contract.
Returns the number of threads that would be available for a task_arena created with the
given constraints and selector. If c.core_type is selectable, the selector is applied
to resolve the core type constraint before computing concurrency; otherwise, the selector is
ignored and the function behaves identically to the single-argument info::default_concurrency.
Selector Requirements#
A selector is a callable object whose call operator has the following effective signature:
int operator()(std::tuple<tbb::core_type_id, std::size_t, std::size_t> core_type_info) const;
The tuple elements are:
Index |
Type |
Description |
|---|---|---|
0 |
|
The core type identifier, as returned by |
1 |
|
Zero-based position of this core type in the vector returned by
|
2 |
|
Total number of available core types ( |
The selector is called once for each core type. Its return value is interpreted as follows:
Score |
Meaning |
|---|---|
Positive |
The core type is selected for use by the arena. A higher score indicates a stronger preference; if the implementation can only use a single core type, it selects the one with the highest score. |
Zero |
The core type is used only if multi-core-type constraints are not supported by the implementation. When there are positive scores and the rest are zero, the zeros act as a fallback to no constraint (rather than falling back to the single best-scored type). |
Negative |
The core type is excluded from use by the arena. |
If all scores are negative, no core type constraint is applied. That is equivalent to
setting constraints::core_type to automatic.
Example#
#define TBB_PREVIEW_TASK_ARENA_CORE_TYPE_SELECTOR 1
#include <oneapi/tbb/task_arena.h>
#include <oneapi/tbb/info.h>
#include <oneapi/tbb/parallel_for.h>
#include <cstdio>
#include <tuple>
#include <vector>
int main() {
tbb::task_arena::constraints c;
c.set_core_type(tbb::task_arena::selectable);
auto selector = [](std::tuple<tbb::core_type_id, std::size_t, std::size_t> core_type) -> int {
auto index = std::get<1>(core_type);
auto total = std::get<2>(core_type);
// Exclude the least performant type when there is more than one;
// rank the rest by index (higher index = higher score).
return (total > 1 && index == 0) ? -1 : static_cast<int>(index);
};
// Query the effective concurrency for these constraints and selector.
int concurrency = tbb::info::default_concurrency(c, selector);
std::printf("Effective concurrency: %d\n", concurrency);
// Create a task arena that uses the selected core types.
tbb::task_arena arena(c, selector);
std::vector<double> data(1000);
arena.execute([&data] {
tbb::parallel_for(std::size_t(0), data.size(),
[&data](std::size_t i) {
data[i] = static_cast<double>(i * i);
});
});
std::printf("data[999] = %.0f\n", data[999]);
}
In this example, a selector excludes the least performant core type (index 0) and ranks the
remaining types by their position. The task_arena is created with
constraints::core_type set to selectable, so the selector is invoked to determine
which core types the arena may use. The info::default_concurrency overload with a selector
is used to query the effective concurrency before creating the arena.