-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Implement P0040R3 parallel specialized memory algorithms #3145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2ab5b2d
bb38f91
dbcf1a4
df9f83e
03d5cbb
f12b6be
c387462
c48f9d7
97c4f54
aa22fc2
d96ccc3
e963846
4aa74a8
9294b4f
c4d8a34
54404af
36fcf35
504b120
a32de8b
7c72ff7
adcc243
9c80ffe
afb20a8
79ca246
a9895ff
930a866
c02455d
300d413
f2ae6e7
9760926
a8c8d54
455223d
ca84b3f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -110,7 +110,8 @@ namespace execution { | |
| // indicates support by element access functions for weakly parallel forward progress guarantees, and for | ||
| // executing interleaved on the same thread, and requests termination on exceptions | ||
| // | ||
| // (at this time, equivalent to sequenced_policy except for the for_each family) | ||
| // (at this time, equivalent to sequenced_policy except for for_each(_n), destroy(_n), | ||
| // uninitialized_default_construct(_n), and uninitialized_value_construct(_n)) | ||
| public: | ||
| using _Standard_execution_policy = int; | ||
| static constexpr bool _Parallelize = false; | ||
|
|
@@ -5050,6 +5051,166 @@ _FwdIt2 adjacent_difference(_ExPo&&, const _FwdIt1 _First, const _FwdIt1 _Last, | |
| _Get_unwrapped_n(_Dest, _Idl_distance<_FwdIt1>(_UFirst, _ULast)), _Pass_fn(_Diff_op))); | ||
| return _Dest; | ||
| } | ||
|
|
||
| _EXPORT_STD template <class _ExPo, class _NoThrowFwdIt, _Enable_if_execution_policy_t<_ExPo> /* = 0 */> | ||
| void destroy(_ExPo&& _Exec, const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) noexcept /* terminates */ { | ||
| // destroy all elements in [_First, _Last) | ||
| _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); | ||
| _STD _Adl_verify_range(_First, _Last); | ||
| using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; | ||
| if constexpr (!is_trivially_destructible_v<_Ty>) { | ||
| _STD for_each(_STD forward<_ExPo>(_Exec), _First, _Last, [](_Ty& _Obj) { _STD _Destroy_in_place(_Obj); }); | ||
| } | ||
| } | ||
|
|
||
| _EXPORT_STD template <class _ExPo, class _NoThrowFwdIt, class _Diff, _Enable_if_execution_policy_t<_ExPo> /* = 0 */> | ||
| _NoThrowFwdIt destroy_n(_ExPo&& _Exec, _NoThrowFwdIt _First, const _Diff _Count_raw) noexcept /* terminates */ { | ||
| // destroy all elements in [_First, _First + _Count) | ||
| _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); | ||
| _Algorithm_int_t<_Diff> _Count = _Count_raw; | ||
| if (_Count <= 0) { | ||
| return _First; | ||
| } | ||
|
|
||
| using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; | ||
| if constexpr (is_trivially_destructible_v<_Ty>) { | ||
| _STD advance(_First, _Count); | ||
| return _First; | ||
| } else { | ||
| return _STD for_each_n( | ||
| _STD forward<_ExPo>(_Exec), _First, _Count, [](_Ty& _Obj) { _STD _Destroy_in_place(_Obj); }); | ||
| } | ||
| } | ||
|
|
||
| _EXPORT_STD template <class _ExPo, class _NoThrowFwdIt, _Enable_if_execution_policy_t<_ExPo> /* = 0 */> | ||
| void uninitialized_default_construct(_ExPo&& _Exec, const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last) noexcept | ||
| /* terminates */ { | ||
| // default-initialize all elements in [_First, _Last) | ||
| _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); | ||
| _STD _Adl_verify_range(_First, _Last); | ||
| using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; | ||
| if constexpr (!is_trivially_default_constructible_v<_Ty>) { | ||
| _STD for_each( | ||
| _STD forward<_ExPo>(_Exec), _First, _Last, [](_Ty& _Obj) { _STD _Default_construct_in_place(_Obj); }); | ||
|
frederick-vs-ja marked this conversation as resolved.
|
||
| } | ||
| } | ||
|
|
||
| _EXPORT_STD template <class _ExPo, class _NoThrowFwdIt, class _Diff, _Enable_if_execution_policy_t<_ExPo> /* = 0 */> | ||
| _NoThrowFwdIt uninitialized_default_construct_n(_ExPo&& _Exec, _NoThrowFwdIt _First, const _Diff _Count_raw) noexcept | ||
| /* terminates */ { | ||
| // default-initialize all elements in [_First, _First + _Count_raw) | ||
| _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); | ||
| _Algorithm_int_t<_Diff> _Count = _Count_raw; | ||
| if (_Count <= 0) { | ||
| return _First; | ||
| } | ||
|
|
||
| using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; | ||
| if constexpr (is_trivially_default_constructible_v<_Ty>) { | ||
| _STD advance(_First, _Count); | ||
| return _First; | ||
| } else { | ||
| return _STD for_each_n( | ||
| _STD forward<_ExPo>(_Exec), _First, _Count, [](_Ty& _Obj) { _STD _Default_construct_in_place(_Obj); }); | ||
| } | ||
| } | ||
|
|
||
| _EXPORT_STD template <class _ExPo, class _NoThrowFwdIt, _Enable_if_execution_policy_t<_ExPo> /* = 0 */> | ||
| void uninitialized_value_construct(_ExPo&&, _NoThrowFwdIt _First, _NoThrowFwdIt _Last) noexcept /* terminates */ { | ||
| // value-initialize all elements in [_First, _Last) | ||
| _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); | ||
| _STD _Adl_verify_range(_First, _Last); | ||
| auto _UFirst = _STD _Get_unwrapped(_First); | ||
| const auto _ULast = _STD _Get_unwrapped(_Last); | ||
|
|
||
| if constexpr (_Use_memset_value_construct_v<decltype(_UFirst)>) { | ||
| _STD _Zero_range(_UFirst, _ULast); | ||
| } else if constexpr (remove_reference_t<_ExPo>::_Parallelize) { | ||
| const size_t _Hw_threads = _CSTD __std_parallel_algorithms_hw_threads(); | ||
| if (_Hw_threads > 1) { // parallelize on multiprocessor machines... | ||
| auto _Count = _STD distance(_UFirst, _ULast); | ||
| if (_Count >= 2) { // ... with at least 2 elements | ||
| _TRY_BEGIN | ||
| using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; | ||
| auto _Ctor_fn = [](_Ty& _Obj) { _STD _Construct_in_place(_Obj); }; | ||
| _Static_partitioned_for_each2<decltype(_UFirst), decltype(_Count), decltype(_Ctor_fn)> _Operation{ | ||
| _Hw_threads, _Count, _Ctor_fn}; | ||
| _Operation._Basis._Populate(_Operation._Team, _UFirst); | ||
| _STD _Run_chunked_parallel_work(_Hw_threads, _Operation); | ||
| return; | ||
| _CATCH(const _Parallelism_resources_exhausted&) | ||
| // fall through to serial case below | ||
| _CATCH_END | ||
| } | ||
| } | ||
|
|
||
| #pragma loop(ivdep) | ||
| for (; _UFirst != _ULast; ++_UFirst) { | ||
| _STD _Construct_in_place(*_UFirst); | ||
| } | ||
| } else if constexpr (remove_reference_t<_ExPo>::_Ivdep) { | ||
| #pragma loop(ivdep) | ||
| for (; _UFirst != _ULast; ++_UFirst) { | ||
| _STD _Construct_in_place(*_UFirst); | ||
| } | ||
| } else { | ||
| for (; _UFirst != _ULast; ++_UFirst) { | ||
| _STD _Construct_in_place(*_UFirst); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| _EXPORT_STD template <class _ExPo, class _NoThrowFwdIt, class _Diff, _Enable_if_execution_policy_t<_ExPo> /* = 0 */> | ||
| _NoThrowFwdIt uninitialized_value_construct_n(_ExPo&&, _NoThrowFwdIt _First, const _Diff _Count_raw) noexcept | ||
| /* terminates */ { | ||
| // value-initialize all elements in [_First, _First + _Count_raw) | ||
| _REQUIRE_PARALLEL_LVALUE_ITERATOR(_NoThrowFwdIt); | ||
| _Algorithm_int_t<_Diff> _Count = _Count_raw; | ||
|
|
||
| if (_Count <= 0) { | ||
| return _First; | ||
| } | ||
|
|
||
| auto _UFirst = _STD _Get_unwrapped_n(_First, _Count); | ||
| if constexpr (_Use_memset_value_construct_v<decltype(_UFirst)>) { | ||
| _STD _Zero_range(_UFirst, _UFirst + _Count); | ||
| _STD _Seek_wrapped(_First, _UFirst + _Count); | ||
| } else if constexpr (remove_reference_t<_ExPo>::_Parallelize) { | ||
| const size_t _Hw_threads = _CSTD __std_parallel_algorithms_hw_threads(); | ||
| if (_Hw_threads > 1 && _Count >= 2) { // parallelize on multiprocessor machines with at least 2 elements | ||
| _TRY_BEGIN | ||
| using _Ty = remove_reference_t<_Iter_ref_t<_NoThrowFwdIt>>; | ||
| auto _Ctor_fn = [](_Ty& _Obj) { _STD _Construct_in_place(_Obj); }; | ||
| _Static_partitioned_for_each2<decltype(_UFirst), decltype(_Count), decltype(_Ctor_fn)> _Operation{ | ||
| _Hw_threads, _Count, _Ctor_fn}; | ||
| _STD _Seek_wrapped(_First, _Operation._Basis._Populate(_Operation._Team, _UFirst)); | ||
| _STD _Run_chunked_parallel_work(_Hw_threads, _Operation); | ||
| return _First; | ||
| _CATCH(const _Parallelism_resources_exhausted&) | ||
| // fall through to serial case below | ||
| _CATCH_END | ||
| } | ||
|
|
||
| #pragma loop(ivdep) | ||
| for (; _Count > 0; --_Count, (void) ++_UFirst) { | ||
| _STD _Construct_in_place(*_UFirst); | ||
| } | ||
| _STD _Seek_wrapped(_First, _UFirst); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No change requested: I observe that we could |
||
| } else if constexpr (remove_reference_t<_ExPo>::_Ivdep) { | ||
| #pragma loop(ivdep) | ||
| for (; _Count > 0; --_Count, (void) ++_UFirst) { | ||
| _STD _Construct_in_place(*_UFirst); | ||
| } | ||
| _STD _Seek_wrapped(_First, _UFirst); | ||
| } else { | ||
| for (; _Count > 0; --_Count, (void) ++_UFirst) { | ||
| _STD _Construct_in_place(*_UFirst); | ||
| } | ||
| _STD _Seek_wrapped(_First, _UFirst); | ||
| } | ||
|
|
||
| return _First; | ||
| } | ||
| _STD_END | ||
| #pragma pop_macro("new") | ||
| _STL_RESTORE_CLANG_WARNINGS | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.