|
1 | 1 | # D0796r1: Supporting Heterogeneous & Distributed Computing Through Affinity
|
2 | 2 |
|
3 |
| -**Date: 2017-10-16** |
| 3 | +**Date: 2017-11-27** |
4 | 4 |
|
5 | 5 | **Audience: SG1, SG14**
|
6 | 6 |
|
@@ -182,20 +182,20 @@ Below is a proposed interface for querying a **system** for its **resource topol
|
182 | 182 |
|
183 | 183 | ```cpp
|
184 | 184 | namespace std::this_system {
|
185 |
| - std::vector<execution_resource &> resources(); |
| 185 | + execution_resource &resource(); |
186 | 186 | }
|
187 | 187 | ```
|
188 | 188 | *Listing 3: Interface for querying the execution resources available within a system*
|
189 | 189 |
|
190 |
| -The **resources** function in the `this_system` namespace will return all **execution resources available** to the current system. |
| 190 | +The **resource** function in the `this_system` namespace will return the root **execution resource** of the current system. |
191 | 191 |
|
192 | 192 | Below is an example of the interface for querying the **execution resources** available to the entire system and printing out the names of each **execution resource**.
|
193 | 193 |
|
194 | 194 | ```cpp
|
195 |
| -auto &resources = std::execution::this_system::resources(); |
| 195 | +auto &resource = std::execution::this_system::resource(); |
196 | 196 |
|
197 |
| -for (auto &r : resources) { |
198 |
| - std::cout << r.name() << std::endl; |
| 197 | +for (int i = 0 ; i < partition_size(); i++) { |
| 198 | + std::cout << resource.partition(i).name() << std::endl; |
199 | 199 | }
|
200 | 200 | ```
|
201 | 201 | *Listing 4: Example of querying the execution resources available within a system*
|
@@ -245,29 +245,6 @@ for (int i = 0; i < resource.partition_size(); i++) {
|
245 | 245 | | Should the interface provide a way of creating an execution context from an execution resource? |
|
246 | 246 | | *Is what is defined here a suitable solution?* |
|
247 | 247 |
|
248 |
| -## Binding Execution and Allocation to a Partition |
249 |
| - |
250 |
| -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. |
251 |
| - |
252 |
| -```cpp |
253 |
| -auto cList = std::execution::this_system::resources(); |
254 |
| -// FindASocketResource is a user-defined function that finds a |
255 |
| -// resource that is a CPU socket in the given resource list |
256 |
| -auto& socket = findASocketResource(cList); |
257 |
| -execution_contexteC{socket} // Associated with the socket |
258 |
| -auto executor = eC.executor(myFunctor); // By transitivity, associated with the socket too |
259 |
| -auto socketAllocator = eC.allocator(); // Retrieve an allocator to the closest memory node |
260 |
| -std::vector<int, socketAllocator> v1(100); |
261 |
| -std::generate(par.on(executor), std::begin(v1), std::end(v1), std::rand); |
262 |
| -``` |
263 |
| -*Listing 8: Example of allocating with affinity to an execution resource* |
264 |
| -
|
265 |
| -The construction of an **execution context** on a component implies affinity (where possible) to the given resource. This guarantees that all executors created from that **execution context** can access the resources and the internal data structures requires to guarantee the placement of the processor. |
266 |
| -
|
267 |
| -Only developers that care about resource placement need to care about obtaining executors and allocations from the correct **execution context** object. Existing code for vectors and STL (including Parallel STL interface) remains unaffected. |
268 |
| -
|
269 |
| -If a particular policy or algorithm requires to access placement information, the resources associated with the passed executor can be retrieved via the link to the **execution context**. |
270 |
| -
|
271 | 248 | ### Importance of topology discovery
|
272 | 249 |
|
273 | 250 | For traditional single CPU systems the execution resources reasoned about using standard constructs such as std::thread, std::this_thread and thread local storage. This is because the C++ memory model requires that a system have **at least one thread of execution, some memory and some I/O capabilities**. This means that for these systems some assumptions can be made about the topology could be made during at compile-time, for example the fact that developers can query always the hardware concurrency available as there is always at least 1 thread or the fact that you can always use thread local storage.
|
@@ -314,6 +291,29 @@ The relative position of two components in the topology is not necessary and ind
|
314 | 291 |
|
315 | 292 | This feature could be easily scaled to heterogeneous and distributed systems as the relative affinity between components can apply to discrete heterogeneous and distributed systems as well.
|
316 | 293 |
|
| 294 | +## Binding Execution and Allocation to a Partition |
| 295 | + |
| 296 | +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. |
| 297 | + |
| 298 | +```cpp |
| 299 | +auto cList = std::execution::this_system::resources(); |
| 300 | +// FindASocketResource is a user-defined function that finds a |
| 301 | +// resource that is a CPU socket in the given resource list |
| 302 | +auto& socket = findASocketResource(cList); |
| 303 | +execution_contexteC{socket} // Associated with the socket |
| 304 | +auto executor = eC.executor(myFunctor); // By transitivity, associated with the socket too |
| 305 | +auto socketAllocator = eC.allocator(); // Retrieve an allocator to the closest memory node |
| 306 | +std::vector<int, socketAllocator> v1(100); |
| 307 | +std::generate(par.on(executor), std::begin(v1), std::end(v1), std::rand); |
| 308 | +``` |
| 309 | +*Listing 8: Example of allocating with affinity to an execution resource* |
| 310 | +
|
| 311 | +The construction of an **execution context** on a component implies affinity (where possible) to the given resource. This guarantees that all executors created from that **execution context** can access the resources and the internal data structures requires to guarantee the placement of the processor. |
| 312 | +
|
| 313 | +Only developers that care about resource placement need to care about obtaining executors and allocations from the correct **execution context** object. Existing code for vectors and STL (including Parallel STL interface) remains unaffected. |
| 314 | +
|
| 315 | +If a particular policy or algorithm requires to access placement information, the resources associated with the passed executor can be retrieved via the link to the **execution context**. |
| 316 | +
|
317 | 317 | # Future Work
|
318 | 318 |
|
319 | 319 | ### Migrating data from memory allocated in one partition to another
|
|
0 commit comments