Line | % of fetches | Source |
---|---|---|
1 | // Copyright (c) 2007-2016 Hartmut Kaiser | |
2 | // | |
3 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
4 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
5 | ||
6 | /// \file parallel/executors/executor_parameter_traits.hpp | |
7 | ||
8 | #if !defined(HPX_PARALLEL_EXECUTOR_PARAMETER_TRAITS_JUL_30_2015_0914PM) | |
9 | #define HPX_PARALLEL_EXECUTOR_PARAMETER_TRAITS_JUL_30_2015_0914PM | |
10 | ||
11 | #include <hpx/config.hpp> | |
12 | #include <hpx/parallel/config/inline_namespace.hpp> | |
13 | #include <hpx/parallel/executors/executor_traits.hpp> | |
14 | #include <hpx/traits/has_member_xxx.hpp> | |
15 | #include <hpx/traits/is_executor_parameters.hpp> | |
16 | #include <hpx/traits/detail/wrap_int.hpp> | |
17 | #include <hpx/util/always_void.hpp> | |
18 | #include <hpx/util/decay.hpp> | |
19 | ||
20 | #include <cstddef> | |
21 | #include <type_traits> | |
22 | #include <utility> | |
23 | #include <vector> | |
24 | ||
25 | namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v3) | |
26 | { | |
27 | /////////////////////////////////////////////////////////////////////////// | |
28 | // Placeholder type to use predefined executor parameters | |
29 | struct sequential_executor_parameters : executor_parameters_tag {}; | |
30 | ||
31 | /////////////////////////////////////////////////////////////////////////// | |
32 | /// \cond NOINTERNAL | |
33 | namespace detail | |
34 | { | |
35 | // If an executor exposes 'executor_parameter_type' this type is | |
36 | // assumed to represent the default parameters for the given executor | |
37 | // type. | |
38 | template <typename Executor, typename Enable = void> | |
39 | struct extract_executor_parameters | |
40 | { | |
41 | // by default, assume sequential execution | |
42 | typedef sequential_executor_parameters type; | |
43 | }; | |
44 | ||
45 | template <typename Executor> | |
46 | struct extract_executor_parameters<Executor, | |
47 | typename hpx::util::always_void< | |
48 | typename Executor::executor_parameters_type | |
49 | >::type> | |
50 | { | |
51 | typedef typename Executor::executor_parameters_type type; | |
52 | }; | |
53 | ||
54 | /////////////////////////////////////////////////////////////////////// | |
55 | // If a parameters type exposes 'has_variable_chunk_size' aliased to | |
56 | // std::true_type it is assumed that the number of loop iterations to | |
57 | // combine is different for each of the generated chunks. | |
58 | template <typename Parameters, typename Enable = void> | |
59 | struct extract_has_variable_chunk_size | |
60 | { | |
61 | // by default, assume equally sized chunks | |
62 | typedef std::false_type type; | |
63 | }; | |
64 | ||
65 | template <typename Parameters> | |
66 | struct extract_has_variable_chunk_size<Parameters, | |
67 | typename hpx::util::always_void< | |
68 | typename Parameters::has_variable_chunk_size | |
69 | >::type> | |
70 | { | |
71 | typedef typename Parameters::has_variable_chunk_size type; | |
72 | }; | |
73 | ||
74 | /////////////////////////////////////////////////////////////////////// | |
75 | template <typename Parameters_> | |
76 | struct processing_units_count_parameter_helper | |
77 | { | |
78 | template <typename Parameters> | |
79 | static std::size_t call(hpx::traits::detail::wrap_int, | |
80 | Parameters && params) | |
81 | { | |
82 | return hpx::get_os_thread_count(); | |
83 | } | |
84 | ||
85 | template <typename Parameters> | |
86 | static auto call(int, Parameters && params) | |
87 | -> decltype(params.processing_units_count()) | |
88 | { | |
89 | return params.processing_units_count(); | |
90 | } | |
91 | ||
92 | static std::size_t call(Parameters_& params) | |
93 | { | |
94 | return call(0, params); | |
95 | } | |
96 | ||
97 | template <typename Parameters> | |
98 | static std::size_t call(Parameters params) | |
99 | { | |
100 | return call(static_cast<Parameters_&>(params)); | |
101 | } | |
102 | }; | |
103 | ||
104 | template <typename Parameters> | |
105 | std::size_t call_processing_units_parameter_count(Parameters && params) | |
106 | { | |
107 | return processing_units_count_parameter_helper< | |
108 | typename hpx::util::decay_unwrap<Parameters>::type | |
109 | >::call(std::forward<Parameters>(params)); | |
110 | } | |
111 | ||
112 | HPX_HAS_MEMBER_XXX_TRAIT_DEF(processing_units_count); | |
113 | ||
114 | /////////////////////////////////////////////////////////////////////// | |
115 | template <typename Parameters_> | |
116 | struct get_chunk_size_helper | |
117 | { | |
118 | template <typename Parameters, typename Executor, typename F> | |
119 | static std::size_t | |
120 | call(hpx::traits::detail::wrap_int, Parameters &&, Executor &&, | |
121 | F &&, std::size_t cores, std::size_t num_tasks) | |
122 | { | |
123 | return num_tasks; // assume sequential execution | |
124 | } | |
125 | ||
126 | template <typename Parameters, typename Executor, typename F> | |
127 | static auto call(int, Parameters && params, Executor && exec, | |
128 | F && f, std::size_t cores, std::size_t num_tasks) | |
129 | -> decltype( | |
130 | params.get_chunk_size(std::forward<Executor>(exec), | |
131 | std::forward<F>(f), cores, num_tasks) | |
132 | ) | |
133 | { | |
134 | return params.get_chunk_size(std::forward<Executor>(exec), | |
135 | std::forward<F>(f), cores, num_tasks); | |
136 | } | |
137 | ||
138 | template <typename Executor, typename F> | |
139 | static std::size_t | |
140 | call(Parameters_& params, Executor && exec, F && f, | |
141 | std::size_t cores, std::size_t num_tasks) | |
142 | { | |
143 | return call(0, params, std::forward<Executor>(exec), | |
144 | std::forward<F>(f), cores, num_tasks); | |
145 | } | |
146 | ||
147 | template <typename Parameters, typename Executor, typename F> | |
148 | static std::size_t | |
149 | call(Parameters params, Executor && exec, F && f, | |
150 | std::size_t cores, std::size_t num_tasks) | |
151 | { | |
152 | return call(static_cast<Parameters_&>(params), | |
153 | std::forward<Executor>(exec), std::forward<F>(f), | |
154 | cores, num_tasks); | |
155 | } | |
156 | }; | |
157 | ||
158 | template <typename Parameters, typename Executor, typename F> | |
159 | std::size_t call_get_chunk_size(Parameters && params, Executor && exec, | |
160 | F && f, std::size_t cores, std::size_t num_tasks) | |
161 | { | |
162 | return get_chunk_size_helper< | |
163 | typename hpx::util::decay_unwrap<Parameters>::type | |
164 | >::call(std::forward<Parameters>(params), | |
165 | std::forward<Executor>(exec), std::forward<F>(f), | |
166 | cores, num_tasks); | |
167 | } | |
168 | ||
169 | HPX_HAS_MEMBER_XXX_TRAIT_DEF(get_chunk_size); | |
170 | ||
171 | /////////////////////////////////////////////////////////////////////// | |
172 | template <typename Parameters_> | |
173 | struct maximal_number_of_chunks_helper | |
174 | { | |
175 | template <typename Parameters, typename Executor> | |
176 | static std::size_t | |
177 | call(hpx::traits::detail::wrap_int, Parameters &&, Executor &&, | |
178 | std::size_t cores, std::size_t num_tasks) | |
179 | { | |
180 | return 4 * cores; // assume 4 times the number of cores | |
181 | } | |
182 | ||
183 | template <typename Parameters, typename Executor> | |
184 | static auto call(int, Parameters && params, Executor && exec, | |
185 | std::size_t cores, std::size_t num_tasks) | |
186 | -> decltype( | |
187 | params.maximal_number_of_chunks( | |
188 | std::forward<Executor>(exec), cores, num_tasks) | |
189 | ) | |
190 | { | |
191 | return params.maximal_number_of_chunks( | |
192 | std::forward<Executor>(exec), cores, num_tasks); | |
193 | } | |
194 | ||
195 | template <typename Executor> | |
196 | static std::size_t | |
197 | call(Parameters_& params, Executor && exec, std::size_t cores, | |
198 | std::size_t num_tasks) | |
199 | { | |
200 | return call(0, params, std::forward<Executor>(exec), cores, | |
201 | num_tasks); | |
202 | } | |
203 | ||
204 | template <typename Parameters, typename Executor> | |
205 | static std::size_t | |
206 | call(Parameters params, Executor && exec, std::size_t cores, | |
207 | std::size_t num_tasks) | |
208 | { | |
209 | return call(static_cast<Parameters_&>(params), | |
210 | std::forward<Executor>(exec), cores, num_tasks); | |
211 | } | |
212 | }; | |
213 | ||
214 | template <typename Parameters, typename Executor> | |
215 | std::size_t call_maximal_number_of_chunks(Parameters && params, | |
216 | Executor && exec, std::size_t cores, std::size_t num_tasks) | |
217 | { | |
218 | return maximal_number_of_chunks_helper< | |
219 | typename hpx::util::decay_unwrap<Parameters>::type | |
220 | >::call(std::forward<Parameters>(params), | |
221 | std::forward<Executor>(exec), cores, num_tasks); | |
222 | } | |
223 | ||
224 | HPX_HAS_MEMBER_XXX_TRAIT_DEF(maximal_number_of_chunks); | |
225 | ||
226 | /////////////////////////////////////////////////////////////////////// | |
227 | template <typename Parameters_> | |
228 | struct reset_thread_distribution_helper | |
229 | { | |
230 | template <typename Parameters, typename Executor> | |
231 | static void call(hpx::traits::detail::wrap_int, Parameters &&, | |
232 | Executor &&) | |
233 | { | |
234 | } | |
235 | ||
236 | template <typename Parameters, typename Executor> | |
237 | static auto call(int, Parameters && params, Executor && exec) | |
238 | -> decltype( | |
239 | params.reset_thread_distribution( | |
240 | std::forward<Executor>(exec)) | |
241 | ) | |
242 | { | |
243 | params.reset_thread_distribution(std::forward<Executor>(exec)); | |
244 | } | |
245 | ||
246 | template <typename Executor> | |
247 | static void call(Parameters_& params, Executor && exec) | |
248 | { | |
249 | call(0, params, std::forward<Executor>(exec)); | |
250 | } | |
251 | ||
252 | template <typename Parameters, typename Executor> | |
253 | static void call(Parameters params, Executor && exec) | |
254 | { | |
255 | call(static_cast<Parameters_&>(params), | |
256 | std::forward<Executor>(exec)); | |
257 | } | |
258 | }; | |
259 | ||
260 | template <typename Parameters, typename Executor> | |
261 | void call_reset_thread_distribution(Parameters && params, | |
262 | Executor && exec) | |
263 | { | |
264 | reset_thread_distribution_helper< | |
265 | typename hpx::util::decay_unwrap<Parameters>::type | |
266 | >::call(std::forward<Parameters>(params), | |
267 | std::forward<Executor>(exec)); | |
268 | } | |
269 | ||
270 | HPX_HAS_MEMBER_XXX_TRAIT_DEF(reset_thread_distribution); | |
271 | ||
272 | /////////////////////////////////////////////////////////////////////// | |
273 | template <typename Parameters_> | |
274 | struct mark_begin_execution_helper | |
275 | { | |
276 | template <typename Parameters> | |
277 | static void call(hpx::traits::detail::wrap_int, Parameters &&) | |
278 | { | |
279 | } | |
280 | ||
281 | template <typename Parameters> | |
282 | static auto call(int, Parameters && params) | |
283 | -> decltype(params.mark_begin_execution()) | |
284 | { | |
285 | params.mark_begin_execution(); | |
286 | } | |
287 | ||
288 | static void call(Parameters_& params) | |
289 | { | |
290 | call(0, params); | |
291 | } | |
292 | ||
293 | template <typename Parameters> | |
294 | static void call(Parameters params) | |
295 | { | |
296 | call(static_cast<Parameters_&>(params)); | |
297 | } | |
298 | }; | |
299 | ||
300 | template <typename Parameters> | |
301 | void call_mark_begin_execution(Parameters && params) | |
302 | { | |
303 | mark_begin_execution_helper< | |
304 | typename hpx::util::decay_unwrap<Parameters>::type | |
305 | >::call(std::forward<Parameters>(params)); | |
306 | } | |
307 | ||
308 | HPX_HAS_MEMBER_XXX_TRAIT_DEF(mark_begin_execution); | |
309 | ||
310 | /////////////////////////////////////////////////////////////////////// | |
311 | template <typename Parameters_> | |
312 | struct mark_end_execution_helper | |
313 | { | |
314 | template <typename Parameters> | |
315 | static void call(hpx::traits::detail::wrap_int, Parameters &&) | |
316 | { | |
317 | } | |
318 | ||
319 | template <typename Parameters> | |
320 | static auto call(int, Parameters && params) | |
321 | -> decltype(params.mark_end_execution()) | |
322 | { | |
323 | params.mark_end_execution(); | |
324 | } | |
325 | ||
326 | static void call(Parameters_& params) | |
327 | { | |
328 | call(0, params); | |
329 | } | |
330 | ||
331 | template <typename Parameters> | |
332 | static void call(Parameters params) | |
333 | { | |
334 | call(static_cast<Parameters_&>(params)); | |
335 | } | |
336 | }; | |
337 | ||
338 | template <typename Parameters> | |
339 | void call_mark_end_execution(Parameters && params) | |
340 | { | |
341 | mark_end_execution_helper< | |
342 | typename hpx::util::decay_unwrap<Parameters>::type | |
343 | >::call(std::forward<Parameters>(params)); | |
344 | } | |
345 | ||
346 | HPX_HAS_MEMBER_XXX_TRAIT_DEF(mark_end_execution); | |
347 | } | |
348 | /// \endcond | |
349 | ||
350 | /////////////////////////////////////////////////////////////////////////// | |
351 | /// The executor_parameter_traits type is used to manage parameters for | |
352 | /// an executor. | |
353 | template <typename Parameters, typename Enable> | |
354 | struct executor_parameter_traits | |
355 | { | |
356 | /// The type of the executor associated with this instance of | |
357 | /// \a executor_traits | |
358 | typedef Parameters executor_parameters_type; | |
359 | ||
360 | /// The compile-time information about whether the number of loop | |
361 | /// iterations to combine is different for each of the generated chunks. | |
362 | /// | |
363 | /// \note This calls extracts parameters_type::has_variable_chunk_size, | |
364 | /// if available, otherwise it returns std::false_type. | |
365 | /// | |
366 | typedef typename detail::extract_has_variable_chunk_size< | |
367 | executor_parameters_type | |
368 | >::type has_variable_chunk_size; | |
369 | ||
370 | /// Return the number of invocations of the given function \a f which | |
371 | /// should be combined into a single task | |
372 | /// | |
373 | /// \param params [in] The executor parameters object to use for | |
374 | /// determining the chunk size for the given number of | |
375 | /// tasks \a num_tasks. | |
376 | /// \param exec [in] The executor object which will be used | |
377 | /// for scheduling of the loop iterations. | |
378 | /// \param f [in] The function which will be optionally scheduled | |
379 | /// using the given executor. | |
380 | /// \param cores [in] The number of cores the number of chunks | |
381 | /// should be determined for. | |
382 | /// \param num_tasks [in] The number of tasks the chunk size should be | |
383 | /// determined for | |
384 | /// | |
385 | /// \note The parameter \a f is expected to be a nullary function | |
386 | /// returning a `std::size_t` representing the number of | |
387 | /// iteration the function has already executed (i.e. which | |
388 | /// don't have to be scheduled anymore). | |
389 | /// | |
390 | template <typename Parameters_, typename Executor, typename F> | |
391 | static std::size_t get_chunk_size(Parameters_ && params, | |
392 | Executor && exec, F && f, std::size_t cores, std::size_t num_tasks) | |
393 | { | |
394 | return detail::call_get_chunk_size(std::forward<Parameters_>(params), | |
395 | std::forward<Executor>(exec), std::forward<F>(f), cores, num_tasks); | |
396 | } | |
397 | ||
398 | /// Return the largest reasonable number of chunks to create for a | |
399 | /// single algorithm invocation. | |
400 | /// | |
401 | /// \param params [in] The executor parameters object to use for | |
402 | /// determining the number of chunks for the given | |
403 | /// number of \a cores. | |
404 | /// \param exec [in] The executor object which will be used | |
405 | /// for scheduling of the loop iterations. | |
406 | /// \param cores [in] The number of cores the number of chunks | |
407 | /// should be determined for. | |
408 | /// \param num_tasks [in] The number of tasks the chunk size should be | |
409 | /// determined for | |
410 | /// | |
411 | template <typename Parameters_, typename Executor> | |
412 | static std::size_t maximal_number_of_chunks( | |
413 | Parameters_ && params, Executor && exec, std::size_t cores, | |
414 | std::size_t num_tasks) | |
415 | { | |
416 | return detail::call_maximal_number_of_chunks( | |
417 | std::forward<Parameters_>(params), std::forward<Executor>(exec), | |
418 | cores, num_tasks); | |
419 | } | |
420 | ||
421 | /// Reset the internal round robin thread distribution scheme for the | |
422 | /// given executor. | |
423 | /// | |
424 | /// \param params [in] The executor parameters object to use for | |
425 | /// resetting the thread distribution scheme. | |
426 | /// \param exec [in] The executor object to use. | |
427 | /// | |
428 | /// \note This calls params.reset_thread_distribution(exec) if it exists; | |
429 | /// otherwise it does nothing. | |
430 | /// | |
431 | template <typename Parameters_, typename Executor> | |
432 | static void reset_thread_distribution(Parameters_ && params, | |
433 | Executor && exec) | |
434 | { | |
435 | detail::call_reset_thread_distribution( | |
436 | std::forward<Parameters_>(params), std::forward<Executor>(exec)); | |
437 | } | |
438 | ||
439 | /// Retrieve the number of (kernel-)threads used by the associated | |
440 | /// executor. | |
441 | /// | |
442 | /// \param params [in] The executor parameters object to use as a | |
443 | /// fallback if the executor does not expose | |
444 | /// | |
445 | /// \note This calls params.processing_units_count() if it exists; | |
446 | /// otherwise it forwards the request to the executor parameters | |
447 | /// object. | |
448 | /// | |
449 | template <typename Parameters_> | |
450 | static std::size_t processing_units_count(Parameters_ && params) | |
451 | { | |
452 | return detail::call_processing_units_parameter_count( | |
453 | std::forward<Parameters_>(params)); | |
454 | } | |
455 | ||
456 | /// Mark the begin of a parallel algorithm execution | |
457 | /// | |
458 | /// \param params [in] The executor parameters object to use as a | |
459 | /// fallback if the executor does not expose | |
460 | /// | |
461 | /// \note This calls params.mark_begin_execution(exec) if it exists; | |
462 | /// otherwise it does nothing. | |
463 | /// | |
464 | template <typename Parameters_> | |
465 | static void mark_begin_execution(Parameters_ && params) | |
466 | { | |
467 | detail::call_mark_begin_execution(std::forward<Parameters_>(params)); | |
468 | } | |
469 | ||
470 | /// Mark the end of a parallel algorithm execution | |
471 | /// | |
472 | /// \param params [in] The executor parameters object to use as a | |
473 | /// fallback if the executor does not expose | |
474 | /// | |
475 | /// \note This calls params.mark_end_execution(exec) if it exists; | |
476 | /// otherwise it does nothing. | |
477 | /// | |
478 | template <typename Parameters_> | |
479 | static void mark_end_execution(Parameters_ && params) | |
480 | { | |
481 | detail::call_mark_end_execution(std::forward<Parameters_>(params)); | |
482 | } | |
483 | }; | |
484 | ||
485 | /////////////////////////////////////////////////////////////////////////// | |
486 | // defined in hpx/traits/is_executor_parameters.hpp | |
487 | /// | |
488 | /// 1. The type is_executor_parameters can be used to detect executor | |
489 | /// parameters types for the purpose of excluding function signatures | |
490 | /// from otherwise ambiguous overload resolution participation. | |
491 | /// 2. If T is the type of a standard or implementation-defined executor, | |
492 | /// is_executor_parameters<T> shall be publicly derived from | |
493 | /// integral_constant<bool, true>, otherwise from | |
494 | /// integral_constant<bool, false>. | |
495 | /// 3. The behavior of a program that adds specializations for | |
496 | /// is_executor_parameters is undefined. | |
497 | /// | |
498 | template <typename T> | |
499 | struct is_executor_parameters; | |
500 | }}} | |
501 | ||
502 | #endif | |
503 |
Copyright (c) 2006-2012 Rogue Wave Software, Inc. All Rights Reserved.
Patents pending.