You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Replace execution_resource::resources with execution_resource::begin
and execution_resource::end.
* Add execution_resource::size.
* Add execution_resource::operator[].
* Add aliases to execution_resource to support new interface.
* Improve woring for execution resource and system topology.
* Update examples to suppoort change.
* Rename this_system::resources to this_system::discover_topology.
Copy file name to clipboardExpand all lines: affinity/cpp-20/d0796r3.md
+83-40Lines changed: 83 additions & 40 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -16,6 +16,10 @@
16
16
17
17
### P0796r3 (SAN 2018)
18
18
19
+
* Make `execution_resource`s iterable by replacing `execution_resource::resources` with `execution_resource::begin` and `execution_resource::end`.
20
+
* Add `size` and `operator[]` for `execution_resource`.
21
+
* Rename `this_system::get_resources` to `this_system::discover_topology`.
22
+
19
23
### P0796r2 (RAP 2018)
20
24
21
25
* Introduce a free function for retrieving the execution resource underlying the current thread of execution.
@@ -211,26 +215,39 @@ Below *(Listing 2)* is an example of executing a parallel task over 8 threads us
211
215
212
216
## Execution resource topology
213
217
214
-
### Execution resources
218
+
### System topology
215
219
216
-
An `execution_resource`is a lightweight structure which acts as an identifier to particular piece of hardware within a system. It can be queried for whether it can allocate memory via `can_place_memory`, whether it can execute work via `can_place_agents`, and for its name via `name`. An `execution_resource` can also represent other `execution_resource`s. We call these *members of* that `execution_resource`, and can be queried via `resources`. Additionally the `execution_resource` which another is a *member of* can be queried via `member_of`. An `execution_resource` can also be queried for the concurrency it can provide, the total number of *threads of execution* supported by that *execution_resource*, and all resources it represents.
220
+
The **system topology**is comprised of a directed acyclic graph (DAG) of **execution resources**, representing all unique hardware and software components available within the system capable of executing work. The root node of the DAG is the **system execution resource**and represents the entire system. Each **execution resource** within the DAG may have any number of child **execution resources** representing a finer granularity of the parent **execution resource**. Every **execution resource** within the **system topology** is exposed via an `execution_resource` object.
217
221
218
-
> [*Note:* Note that an execution resource is not limited to resources which execute work, but also a general resource where no execution can take place but memory can be allocated such as off-chip memory. *--end note*]
222
+
The **system topology** can be discovered by calling `this_system::discover_topology`. This will discover all **execution resources** available within the system and construct the **system topology** DAG, describing a read-only snapshot at the point of the call, and then return an `execution_resource` object exposing the **system execution resource**.
219
223
220
-
> [*Note:*The intention is that the actual implementation details of a resource topology are described in an execution context when required. This allows the execution resource objects to be lightweight objects that serve as identifiers that are only referenced. *--end note*]
224
+
> [*Note:*A call to `this_system::discover_topology` may invoke C++ library calls, system calls or third party library APIs required to discover certain **execution resources**. *--end note*]
221
225
222
-
### System topology
226
+
### Execution resources
227
+
228
+
An `execution_resource` is a lightweight structure which identifies a particular **execution resource** within a snapshot of the **system topology**. It can be queried for whether the associated **execution resource** can allocate memory via `can_place_memory`, whether the associated **execution resource** can execute work via `can_place_agents`, and for a name via `name`.
223
229
224
-
The system topology is made up of a number of system-level `execution_resource`s, which can be queried through `this_system::get_resources` which returns a `std::vector`. A run-time library may initialize the `execution_resource`s available within the system dynamically. However, this must be done before `main` is called, given that after that point, the system topology may not change.
230
+
An `execution_resource` object can be queried for a pointer to it's parent `execution_resource` via `member_of`, and can also be iterated over for it's child `execution_resource`s via `begin` and `end`.
225
231
226
-
Below *(Listing 3)* is an example of iterating over the system-level resources and printing out their capabilities.
232
+
An `execution_resource` object can also be queried for the amount concurrency it can provide, the total number of **threads of execution** supported by the associated **execution resource**.
233
+
234
+
> [*Note:* An **execution resource** is not limited to resources which execute work, but also a general resource where no execution can take place but memory can be allocated such as off-chip memory. *--end note*]
235
+
236
+
Below *(Listing 3)* is an example of iterating over every **execution resource** within the **system topology** and printing out their capabilities.
227
237
228
238
```cpp
229
-
for (auto res : execution::this_system::get_resources()) {
230
-
std::cout << res.name() `\n`;
231
-
std::cout << res.can_place_memory() << `\n`;
232
-
std::cout << res.can_place_agents() << `\n`;
233
-
std::cout << res.concurrency() << `\n`;
239
+
voidprint_topology(const execution::execution_resource &resource, int indent = 0) {
240
+
for (int i = 0; i < indent; i++) { std::cout << " "; }
auto relativeLatency = relativeLatency01 > relativeLatency02;
255
271
```
@@ -264,27 +280,27 @@ The `execution_context` class provides an abstraction for managing a number of l
264
280
Below *(Listing 5)* is an example of how this extended interface could be used to construct an *execution context* from an *execution resource* which is retrieved from the *system’s resource topology*. Once an *execution context* is constructed it can then still be queried for its *execution resource*, and that *execution resource* can be further partitioned.
auto &systemLevelResource = execContext.resource();
287
+
auto &execResource = execContext.resource();
272
288
273
-
// resource[0] should be equal to execResource
289
+
// systemResource[0] should be equal to execResource
274
290
275
-
for (auto res : systemLevelResource.resources()) {
276
-
std::cout << res.name() << `\n`;
291
+
for (const execution::execution_resource res : execResource()) {
292
+
std::cout << res.name() << "\n";
277
293
}
278
294
```
279
295
*Listing 5: Example of constructing an execution context from an execution resource*
280
296
281
297
When creating an `execution_context` from a given `execution_resource`, the executors and allocators associated with it are bound to that `execution_resource`. For example, when creating an `execution_resource` from a CPU socket resource, all executors associated with the given socket will spawn execution agents with affinity to the socket partition of the system *(Listing 6)*.
282
298
283
299
```cpp
284
-
auto cList = std::execution::this_system::get_resources();
300
+
auto systemResource = std::this_system::discover_topology();
285
301
// FindASocketResource is a user-defined function that finds a
286
302
// resource that is a CPU socket in the given resource list
@@ -447,7 +476,7 @@ The `execution_resource` class provides an abstraction over a system's hardware,
447
476
448
477
### `execution_resource` constructors
449
478
450
-
execution_resource();
479
+
execution_resource() = delete;
451
480
452
481
> [*Note:* An implementation of `execution_resource` is permitted to provide non-public constructors to allow other objects to construct them. *--end note*]
453
482
@@ -468,25 +497,37 @@ The `execution_resource` class provides an abstraction over a system's hardware,
468
497
469
498
*Returns:* The total concurrency available to this resource. More specifically, the number of *threads of execution* collectively available to this `execution_resource` and any resources which are *members of*, recursively.
470
499
471
-
std::vector<resource> resources() const noexcept;
500
+
size_type size() const noexcept;
501
+
502
+
*Returns:* The number of child `execution_resource`s.
503
+
504
+
const_iterator begin() const noexcept;
472
505
473
-
*Returns:* All `execution_resource`s which are *members of* this resource.
506
+
*Returns:* A const iterator to the beggining of the child `execution_resource`s.
507
+
508
+
const_iterator end() const noexcept;
509
+
510
+
*Returns:* A const iterator to the end of the child `execution_resource`s.
*Returns:* The `execution_resource` which this resource is a *member of*.
518
+
*Returns:* The parent `execution_resource`.
478
519
479
520
std::string name() const noexcept;
480
521
481
522
*Returns:* An implementation defined string.
482
523
483
524
bool can_place_memory() const noexcept;
484
525
485
-
*Returns:* If this resource is capable of allocating memory with affinity, 'true'.
526
+
*Returns:* If the associated **execution resource* is capable of allocating memory with affinity, 'true'.
486
527
487
528
bool can_place_agent() const noexcept;
488
529
489
-
*Returns:* If this resource is capable of execute with affinity, 'true'.
530
+
*Returns:* If the associated **execution resource* is capable of execute with affinity, 'true'.
490
531
491
532
## Class `execution_context`
492
533
@@ -589,17 +630,19 @@ The `affinity_query` class template provides an abstraction for a relative affin
589
630
590
631
## Free functions
591
632
592
-
### `this_system::get_resources`
633
+
### `this_system::discover_topology`
634
+
635
+
The free function `this_system::discover_topology` is provided for discovering the **system topology**.
593
636
594
-
The free function `this_system::get_resources` is provided for retrieving the `execution_resource`s which encapsulate the hardware platforms available within the system. We refer to these resources as the *system level resources*.
*Returns:* An `execution_resource` object exposing the **system execution resource**.
597
640
598
-
*Returns:*An `std::vector` containing all *system level resources*.
641
+
*Requires:*If `this_system::discover_topology().size() > 0`, `this_system::discover_topology()[0]` be the `execution_resource` use by `std::thread`. Calls to `this_system::discover_topology()` may not introduce a data race with any other call to `this_system::discover_topology()`.
599
642
600
-
*Requires:*If `this_system::get_resources().size() > 0`, `this_system::get_resources()[0]` be the `execution_resource` use by `std::thread`. The value returned by `this_system::get_resources()` be the same at any point after the invocation of `main`.
643
+
*Effects:*Discovers all **execution resources** available within the system and constructs the **system topology** DAG, describing a read-only snapshot at the point of the call.
601
644
602
-
> [*Note:*Returning a `std::vector` allows users to potentially manipulate the container of `execution_resource`s after it is returned. We may want to replace this at a later date with an alternative type which is more restrictive, such as a range or span. *--end note*]
645
+
*Throws:*Any exception thrown as a result of **system topology** discovery.
0 commit comments