Skip to content

Commit c3a74bc

Browse files
author
Gordon Brown
committed
CP013: Finish adding the new proposals.
* Minor fixes for typos. * Have execution_context::memory_resource() return a reference instead of a pointer. * Add execution_context::allocator(). * Add execution_context::pmr_memory_resource_type alias. * Fill in requirements for execution_resource, execution_context, affinity_query and this_system::resources().
1 parent d8379cb commit c3a74bc

File tree

1 file changed

+78
-52
lines changed

1 file changed

+78
-52
lines changed

affinity/cpp-20/d0796r1.md

Lines changed: 78 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ One strategy to improve applications' performance, given the importance of affin
3737

3838
Operating systems (OSes) traditionally take responsibility for assigning threads or processes to run on processing units. However, OSes may use high-level policies for this assignment that do not necessarily match the optimal usage pattern for a given application. Application developers must leverage the placement of memory and **placement of threads** for best performance on current and future architectures. For C++ developers to achieve this, native support for **placement of threads and memory** is critical for application portability. We will refer to this as the **affinity problem**.
3939

40-
The affinity problem is especially challenging for applications whose behavior changes over time or is hard to predict, or when different applications interfere with each other's performance. Today, most OSes already can group processing units according to their locality and distribute processes, while keeping threads close to the initial thread, or even avoid migrating threads and maintain first touch policy. Nevertheless, most pro grams can change their work distribution, especially in the presence of nested parallelism.
40+
The affinity problem is especially challenging for applications whose behavior changes over time or is hard to predict, or when different applications interfere with each other's performance. Today, most OSes already can group processing units according to their locality and distribute processes, while keeping threads close to the initial thread, or even avoid migrating threads and maintain first touch policy. Nevertheless, most programs can change their work distribution, especially in the presence of nested parallelism.
4141

4242
Frequently, data is initialized at the beginning of the program by the initial thread and is used by multiple threads. While automatic thread migration has been implemented in some OSes, migration may have high overhead. In an optimal case, the OS may automatically detect which thread access which data most frequently, or it may replicate data which is read by multiple threads, or migrate data which is modified and used by threads residing on remote locality groups. However, the OS often does a reasonable job, if the machine is not overloaded, if the application carefully used first-touch allocation, and if the program does not change its behavior with respect to locality.
4343

@@ -128,10 +128,10 @@ There are some additional challenges which we have been investigating but are no
128128
~execution_resource();
129129
130130
size_t concurrency() const noexcept;
131-
size_t partition_size() const noexcept;
132131
133-
const execution_resource &partition(size_t) const noexcept;
134-
const execution_resource &member_of() const noexcept;
132+
std::vector<resource> resources() const noexcept;
133+
134+
const execution_resource member_of() const noexcept;
135135
136136
std::string name() const noexcept;
137137
@@ -145,17 +145,23 @@ There are some additional challenges which we have been investigating but are no
145145
class execution_context {
146146
public:
147147
148-
using executor_type = __unspecfied__;
148+
using executor_type = see-below;
149+
150+
using pmr_memory_resource_type = see-below;
151+
152+
using allocator_type = see-below;
149153
150-
execution_context(const execution_resource &);
154+
execution_context(const execution_resource &) noexcept;
151155
152156
~execution_context();
153157
154158
const execution_resource &resource() const noexcept;
155159
156-
executor_type executor() noexcept;
160+
executor_type executor() const;
157161
158-
pmr::memory_resource *memory_resource() noexcept;
162+
pmr_memory_resource_type &memory_resource() const;
163+
164+
allocator_type allocator() const;
159165
160166
};
161167
@@ -168,10 +174,10 @@ There are some additional challenges which we have been investigating but are no
168174
class affinity_query {
169175
public:
170176
171-
using native_affinity_type = __unspecified__;
172-
using error_type = __unspecified__
177+
using native_affinity_type = see-below;
178+
using error_type = see-below
173179
174-
affinity_query(execution_resource &&, execution_resource &&);
180+
affinity_query(execution_resource &&, execution_resource &&) noexcept;
175181
176182
~affinity_query();
177183
@@ -200,110 +206,124 @@ There are some additional challenges which we have been investigating but are no
200206
201207
## Class `execution_resource`
202208
203-
The `execution_resource` class provides an abstraction over a system's hardware capable of memory allocation, execution of light weight exeution agents or both.
209+
The `execution_resource` class provides an abstraction over a system's hardware capable of memory allocation, execution of light weight exeution agents or both. An `execution_resource` can represent further `execution_resource`s, these `execution_resource`s are said to be *members of* this `execution_resource`.
204210
205211
> [*Note:* The `execution_resource` is required to be implemented such that the underlying software abstraction is initialised on when the `execution_resource` is constructed, maintained through reference counting and cleaned up on destruction of the final reference. *--end note*]
206212
207213
### `execution_resource` constructors
208214
209-
execution_resource() = delete;
215+
execution_resource();
210216
211217
> [*Note:* An implementation of `execution_resource` is permitted to provide non-public constructors to allow other objects to construct them. *--end note*]
212218
213219
### `execution_resource` assignment
214220
215-
The `execution_resource` class is not `CopyConstructible` (C++Std [copyconstructible]).
216-
217221
execution_resource(const execution_resource &);
218222
execution_resource(execution_resource &&);
219223
execution_resource &operator=(const execution_resource &);
220224
execution_resource &operator=(execution_resource &&);
221225
222226
### `execution_resource` destructor
223227
224-
The `execution_resource` class is not `Destructible` (C++Std [destructible]).
225-
226-
~execution_resource() = delete;
228+
~execution_resource();
227229
228230
### `execution_resource` operations
229231
230232
size_t concurrency() const noexcept;
231233
232-
*Returns:*
234+
*Returns:* The collective concurrency available to this resource. More pecifically, the number of *threads of execution* collectively available to this `execution_resource` and any resources which are *members of*, recursively.
233235
234-
size_t partition_size() const noexcept;
236+
std::vector<resource> resources() const noexcept;
235237
236-
*Returns:*
237-
238-
const execution_resource &partition(size_t) const noexcept;
239-
240-
*Returns:*
238+
*Returns:* All `execution_resource`s which are *members of* this resource.
241239
242240
const execution_resource &member_of() const noexcept;
243241
244-
*Returns:*
242+
*Returns:* The `execution_resource` which this resource is a *member of*.
245243
246244
std::string name() const noexcept;
247245
248-
*Returns:*
246+
*Returns:* An implementation defined string.
249247
250248
bool can_place_memory() const noexcept;
251249
252-
*Returns:*
250+
*Returns:* If this resource is capable of allocating memory with affinity, 'true'.
253251
254252
bool can_place_agent() const noexcept;
255253
256-
*Returns:*
254+
*Returns:* If this resource is capable of execute with affinity, 'true'.
257255
258256
## Class `execution_context`
259257
260-
The `execution_context` class provides an abstraction for managing a number of light weight execution agents executing work on an `execution_resource` and any `execution_resource`s encapsulated by it.
258+
The `execution_context` class provides an abstraction for managing a number of light weight execution agents executing work on an `execution_resource` and any `execution_resource`s encapsulated by it. The `execution_resource` which an `execution_context` encapsulates is refered to as the *contained resource*.
259+
260+
### `execution_context` types
261+
262+
using executor_type = see-below;
263+
264+
*Requires:* `executor_type` is an implementation defined class which satifies the general executor requires, as specified by P0443r5.
261265
262-
### `execution_context` member aliases
266+
using pmr_memory_resource_type = see-below;
263267
264-
using executor_type = __unspecfied__;
268+
*Requires:* `pmr_memory_resource_type` is an implementation defined class which inherits from `std::pmr::memory_resource`.
265269
266-
*Requires:*
270+
using allocator_type = see-below;
271+
272+
*Requires:* `allocator_type` is an implementation defined allocator class.
267273
268274
### `execution_context` constructors
269275
270-
execution_context(const execution_resource &);
276+
execution_context(const execution_resource &) noexcept;
277+
278+
*Effects:* Constructs an `execution_context` with the provided resource as the *contained resource*.
271279
272280
### `execution_context` destructor
273281
274282
~execution_context();
275283
284+
*Effects:* May or may not block to wait any work bveing executed on the *contained resource*.
285+
276286
### `execution_context` operators
277287
278288
const execution_resource &resource() const noexcept;
279289
280-
*Returns:*
290+
*Returns:* A const-reference to the *contained resource*.
281291
282292
executor_type executor() noexcept;
283293
284-
*Returns:*
294+
*Returns:* An executor of type `executor_type` capable of executing work with affinity to the *contained resource*.
295+
296+
*Throws:* An exception `!this->resource().can_place_agents()`.
297+
298+
pmr::memory_resource &memory_resource() noexcept;
285299
286-
pmr::memory_resource *memory_resource() noexcept;
300+
*Returns:* A reference to a polymorphic memory resource of type `pmr_memory_resource_type` capable of allocating with affinity to the *contained resource*.
287301
288-
*Returns:*
302+
*Throws:* If `!this->resource().can_place_memory()`.
303+
304+
allocator_type allocator() const;
305+
306+
*Returns:* An allocator of type `allocator_type` capable of allocating with affinity to the *contained resource*.
307+
308+
*Throws:* If `!this->resource().can_place_memory()`.
289309
290310
## Class template `affinity_query`
291311
292312
The `affinity_query` class template provides an abstraction for a relative affinity value between two `execution_resource`s, derived from a particular `affinity_operation` and `affinity_metric`.
293313
294-
### `affinity_query` member aliases
314+
### `affinity_query` types
295315
296-
using native_affinity_type = __unspecfied__;
316+
using native_affinity_type = see-below;
297317
298-
*Requires:*
318+
*Requires:* `native_affinity_type` is an implementation defined integral type capable of storing a native affinity value.
299319
300-
using error_type = __unspecfied__;
320+
using error_type = see-below;
301321
302-
*Requires:*
322+
*Requires:* `error_type` is an implementation defined integral type capable of storing the an error code value.
303323
304324
### `affinity_query` constructors
305325
306-
affinity_query(const execution_resource &, const execution_resource &);
326+
affinity_query(const execution_resource &, const execution_resource &) noexcept;
307327
308328
### `affinity_query` destructor
309329
@@ -317,22 +337,28 @@ The `affinity_query` class template provides an abstraction for a relative affin
317337
318338
### `affinity_query` comparisons
319339
320-
friend expected<size_t> operator==(const affinity_query&, const affinity_query&);
321-
friend expected<size_t> operator!=const affinity_query&, const affinity_query&);
322-
friend expected<size_t> operator<(const affinity_query&, const affinity_query&);
323-
friend expected<size_t> operator>(const affinity_query&, const affinity_query&);
324-
friend expected<size_t> operator<=(const affinity_query&, const affinity_query&);
325-
friend expected<size_t> operator>=(const affinity_query&, const affinity_query&);
340+
friend expected<size_t, error_type> operator==(const affinity_query&, const affinity_query&);
341+
friend expected<size_t, error_type> operator!=const affinity_query&, const affinity_query&);
342+
friend expected<size_t, error_type> operator<(const affinity_query&, const affinity_query&);
343+
friend expected<size_t, error_type> operator>(const affinity_query&, const affinity_query&);
344+
friend expected<size_t, error_type> operator<=(const affinity_query&, const affinity_query&);
345+
friend expected<size_t, error_type> operator>=(const affinity_query&, const affinity_query&);
326346
327-
*Returns:*
347+
*Returns:* An `expected<size_t, error_type>` where,
348+
* if the affinity query was succesful, the value of type `size_t` represents the magnitude of the relative affinity;
349+
* if the affinity query was not successful, the error is an error of type `error_type` which represents the reason for affinity query failed.
350+
351+
> [*Note:* An affinity query is permitted to fail if affinity between the two execution resources cannot be calculated for any reason, such as the resources are of different vendors or communication between the resources is not possible. *--end note*]
328352
329353
> [*Note:* The comparison operators rely on the availability of the `expected` class template (see [P0323r4: std::expected][p0323r4]), if this does not become available then an alternative error/value construct will be adopted instead. *--end note*]
330354
331355
## Free functions
332356
357+
The free function `this_system::resources` is provided for retrieving the `execution_resource`s which encapsualte the hardware platforms available within the system, these are refered to as the *system level resources*.
358+
333359
std::vector<execution_resource> resources() noexcept;
334360
335-
*Returns:* A std::vector containing all system level resources.
361+
*Returns:* A std::vector containing all *system level resources*.
336362
337363
*Requires:* If `resources().size() > 0`, `resources()[0]` be the `execution_resource` corroponding to the current thread of execution. The value returned by `resources()` be the same at any point after the invocation of `main`.
338364

0 commit comments

Comments
 (0)