From 68b543673616123bf793de762d63d243530fb969 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Mon, 11 Sep 2023 12:35:07 +0800 Subject: [PATCH 01/14] add noexcept for _Ref_fn --- stl/inc/xutility | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 880293a0d71..8478b1ef221 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -541,7 +541,8 @@ struct less_equal { template struct _Ref_fn { // pass function object by value as a reference template - constexpr decltype(auto) operator()(_Args&&... _Vals) { // forward function call operator + constexpr decltype(auto) operator()(_Args&&... _Vals) noexcept( + is_nothrow_invocable_v<_Fx&, _Args&&...>) { // forward function call operator if constexpr (is_member_pointer_v<_Fx>) { return _STD invoke(_Fn, _STD forward<_Args>(_Vals)...); } else { From 38a1ef4357498f15a1f24d22cc6b2816e70743c5 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Mon, 11 Sep 2023 12:51:53 +0800 Subject: [PATCH 02/14] avoid copying large comp --- stl/inc/queue | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/stl/inc/queue b/stl/inc/queue index 4ea1df73500..c5d96ee6b91 100644 --- a/stl/inc/queue +++ b/stl/inc/queue @@ -246,40 +246,40 @@ public: : c(), comp(_Pred) {} priority_queue(const _Pr& _Pred, const _Container& _Cont) : c(_Cont), comp(_Pred) { - _STD make_heap(c.begin(), c.end(), comp); + _Make_heap(); } priority_queue(const _Pr& _Pred, _Container&& _Cont) : c(_STD move(_Cont)), comp(_Pred) { - _STD make_heap(c.begin(), c.end(), comp); + _Make_heap(); } template , int> = 0> priority_queue(_InIt _First, _InIt _Last, const _Pr& _Pred, const _Container& _Cont) : c(_Cont), comp(_Pred) { c.insert(c.end(), _First, _Last); - _STD make_heap(c.begin(), c.end(), comp); + _Make_heap(); } template , int> = 0> priority_queue(_InIt _First, _InIt _Last) : c(_First, _Last), comp() { - _STD make_heap(c.begin(), c.end(), comp); + _Make_heap(); } template , int> = 0> priority_queue(_InIt _First, _InIt _Last, const _Pr& _Pred) : c(_First, _Last), comp(_Pred) { - _STD make_heap(c.begin(), c.end(), comp); + _Make_heap(); } template , int> = 0> priority_queue(_InIt _First, _InIt _Last, const _Pr& _Pred, _Container&& _Cont) : c(_STD move(_Cont)), comp(_Pred) { c.insert(c.end(), _First, _Last); - _STD make_heap(c.begin(), c.end(), comp); + _Make_heap(); } #if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 template <_Container_compatible_range<_Ty> _Rng> priority_queue(from_range_t, _Rng&& _Range, const _Pr& _Pred = _Pr()) : c(_RANGES to<_Container>(_STD forward<_Rng>(_Range))), comp(_Pred) { - _STD make_heap(c.begin(), c.end(), comp); + _Make_heap(); } #endif // _HAS_CXX23 && defined(__cpp_lib_concepts) @@ -295,12 +295,12 @@ public: template , int> = 0> priority_queue(const _Pr& _Pred, const _Container& _Cont, const _Alloc& _Al) : c(_Cont, _Al), comp(_Pred) { - _STD make_heap(c.begin(), c.end(), comp); + _Make_heap(); } template , int> = 0> priority_queue(const _Pr& _Pred, _Container&& _Cont, const _Alloc& _Al) : c(_STD move(_Cont), _Al), comp(_Pred) { - _STD make_heap(c.begin(), c.end(), comp); + _Make_heap(); } template , int> = 0> @@ -315,14 +315,14 @@ public: template && uses_allocator_v<_Container, _Alloc>, int> = 0> priority_queue(_InIt _First, _InIt _Last, const _Alloc& _Al) : c(_First, _Last, _Al), comp() { - _STD make_heap(c.begin(), c.end(), comp); + _Make_heap(); } template && uses_allocator_v<_Container, _Alloc>, int> = 0> priority_queue(_InIt _First, _InIt _Last, const _Pr& _Pred, const _Alloc& _Al) : c(_First, _Last, _Al), comp(_Pred) { - _STD make_heap(c.begin(), c.end(), comp); + _Make_heap(); } template , int> = 0> priority_queue(from_range_t, _Rng&& _Range, const _Pr& _Pred, const _Alloc& _Al) : c(_RANGES to<_Container>(_STD forward<_Rng>(_Range), _Al)), comp(_Pred) { - _STD make_heap(c.begin(), c.end(), comp); + _Make_heap(); } template <_Container_compatible_range<_Ty> _Rng, class _Alloc, enable_if_t, int> = 0> priority_queue(from_range_t, _Rng&& _Range, const _Alloc& _Al) : c(_RANGES to<_Container>(_STD forward<_Rng>(_Range), _Al)), comp() { - _STD make_heap(c.begin(), c.end(), comp); + _Make_heap(); } #endif // _HAS_CXX23 && defined(__cpp_lib_concepts) @@ -371,12 +371,12 @@ public: void push(const value_type& _Val) { c.push_back(_Val); - _STD push_heap(c.begin(), c.end(), comp); + _STD push_heap(c.begin(), c.end(), _STD _Pass_fn(comp)); } void push(value_type&& _Val) { c.push_back(_STD move(_Val)); - _STD push_heap(c.begin(), c.end(), comp); + _STD push_heap(c.begin(), c.end(), _STD _Pass_fn(comp)); } #if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 @@ -388,18 +388,18 @@ public: _RANGES copy(_Range, back_insert_iterator{c}); } - _STD make_heap(c.begin(), c.end(), comp); + _Make_heap(); } #endif // _HAS_CXX23 && defined(__cpp_lib_concepts) template void emplace(_Valty&&... _Val) { c.emplace_back(_STD forward<_Valty>(_Val)...); - _STD push_heap(c.begin(), c.end(), comp); + _STD push_heap(c.begin(), c.end(), _STD _Pass_fn(comp)); } void pop() { - _STD pop_heap(c.begin(), c.end(), comp); + _STD pop_heap(c.begin(), c.end(), _STD _Pass_fn(comp)); c.pop_back(); } @@ -410,6 +410,11 @@ public: swap(comp, _Right.comp); // intentional ADL } +private: + void _Make_heap() { + _STD make_heap(c.begin(), c.end(), _STD _Pass_fn(comp)); + } + protected: _Container c{}; _Pr comp{}; From b8dc640996c96935479f0f910b9f87bbf60362a7 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Sun, 10 Sep 2023 11:37:53 +0800 Subject: [PATCH 03/14] add benchmark --- benchmarks/CMakeLists.txt | 3 +- benchmarks/src/priority_queue_push_range.cpp | 87 ++++++++++++++++++++ 2 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 benchmarks/src/priority_queue_push_range.cpp diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index d9b35a2e68a..6a9c24343e7 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -108,5 +108,6 @@ endfunction() add_benchmark(bitset_to_string src/bitset_to_string.cpp) add_benchmark(locale_classic src/locale_classic.cpp) add_benchmark(path_lexically_normal src/path_lexically_normal.cpp) +add_benchmark(priority_queue_push_range src/priority_queue_push_range.cpp) add_benchmark(random_integer_generation src/random_integer_generation.cpp) -add_benchmark(std_copy src/std_copy.cpp) +add_benchmark(std_copy src/std_copy.cpp) \ No newline at end of file diff --git a/benchmarks/src/priority_queue_push_range.cpp b/benchmarks/src/priority_queue_push_range.cpp new file mode 100644 index 00000000000..4c2406793d7 --- /dev/null +++ b/benchmarks/src/priority_queue_push_range.cpp @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +namespace { + constexpr size_t vec_size = 8000; + + template + auto create_vec(size_t vsize, function transform) { + vector vec(vsize); + for (mt19937_64 rnd(1); auto& e : vec) { + e = transform(rnd()); + } + return vec; + } + + template + T cast_to(uint64_t val) { + return static_cast(val); + } + + const auto vec_u8 = create_vec(vec_size, cast_to); + const auto vec_u16 = create_vec(vec_size, cast_to); + const auto vec_u32 = create_vec(vec_size, cast_to); + const auto vec_u64 = create_vec(vec_size, cast_to); + const auto vec_float = create_vec(vec_size, cast_to); + const auto vec_double = create_vec(vec_size, cast_to); + + const auto vec_str = + create_vec(vec_size, [](uint64_t val) { return to_string(static_cast(val)); }); + const auto vec_wstr = + create_vec(vec_size, [](uint64_t val) { return to_wstring(static_cast(val)); }); + + template + void BM_push_range(benchmark::State& state) { + const size_t frag_size = static_cast(state.range(0)); + + for (auto _ : state) { + priority_queue que; + span spn{Data}; + + while (!spn.empty()) { + size_t take_size = min(spn.size(), frag_size); + que.push_range(spn.subspan(0, take_size)); + spn = spn.subspan(take_size); + } + benchmark::DoNotOptimize(que); + } + } + + template + void putln(const benchmark::State&) { + static bool b = [] { + puts(""); + return true; + }(); + } +} // namespace + +#define TEST_PUSH_RANGE(T, source) \ + BENCHMARK(BM_push_range) \ + ->Setup(putln<__LINE__>) \ + ->RangeMultiplier(100) \ + ->Range(1, vec_size) \ + ->Arg(vec_size / 2 + 1); + +TEST_PUSH_RANGE(uint8_t, vec_u8); +TEST_PUSH_RANGE(uint16_t, vec_u16); +TEST_PUSH_RANGE(uint32_t, vec_u32); +TEST_PUSH_RANGE(uint64_t, vec_u64); +TEST_PUSH_RANGE(float, vec_float); +TEST_PUSH_RANGE(double, vec_double); + +TEST_PUSH_RANGE(string_view, vec_str); +TEST_PUSH_RANGE(string, vec_str); +TEST_PUSH_RANGE(wstring_view, vec_wstr); +TEST_PUSH_RANGE(wstring, vec_wstr); + +BENCHMARK_MAIN(); From 3f32401e9b6b05fe92779d6567cd9d74c54d481c Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Mon, 11 Sep 2023 13:03:12 +0800 Subject: [PATCH 04/14] avoid remaking the whole heap when append size is not huge --- stl/inc/queue | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/stl/inc/queue b/stl/inc/queue index c5d96ee6b91..58c61a980e4 100644 --- a/stl/inc/queue +++ b/stl/inc/queue @@ -382,13 +382,25 @@ public: #if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 template <_Container_compatible_range<_Ty> _Rng> void push_range(_Rng&& _Range) { + const size_type _Old_size = c.size(); + if constexpr (requires { c.append_range(_Range); }) { c.append_range(_Range); } else { _RANGES copy(_Range, back_insert_iterator{c}); } - _Make_heap(); + const size_type _New_size = c.size(); + if (_New_size / 2 > _Old_size) { + _Make_heap(); + } else { + const auto _Begin = _STD _Get_unwrapped(c.begin()); + auto _Heap_end = _Begin + _Old_size; + const auto _End = _STD _Get_unwrapped(c.end()); + while (_Heap_end != _End) { + _STD push_heap(_Begin, ++_Heap_end, _STD _Pass_fn(comp)); + } + } } #endif // _HAS_CXX23 && defined(__cpp_lib_concepts) From 2305bcaf49bbd4113f92d6550de10c13de9d35c1 Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Wed, 13 Sep 2023 13:09:24 +0800 Subject: [PATCH 05/14] restore empty line --- benchmarks/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 6a9c24343e7..df61acfb144 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -110,4 +110,4 @@ add_benchmark(locale_classic src/locale_classic.cpp) add_benchmark(path_lexically_normal src/path_lexically_normal.cpp) add_benchmark(priority_queue_push_range src/priority_queue_push_range.cpp) add_benchmark(random_integer_generation src/random_integer_generation.cpp) -add_benchmark(std_copy src/std_copy.cpp) \ No newline at end of file +add_benchmark(std_copy src/std_copy.cpp) From b676d183f23cbee2c98b4097dc44f15372c1ec8b Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Wed, 13 Sep 2023 13:57:25 +0800 Subject: [PATCH 06/14] make c++14 compatible --- stl/inc/xutility | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 8478b1ef221..459ac900540 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -542,7 +542,7 @@ template struct _Ref_fn { // pass function object by value as a reference template constexpr decltype(auto) operator()(_Args&&... _Vals) noexcept( - is_nothrow_invocable_v<_Fx&, _Args&&...>) { // forward function call operator + _Select_invoke_traits<_Fx&, _Args...>::_Is_nothrow_invocable::value) { // forward function call operator if constexpr (is_member_pointer_v<_Fx>) { return _STD invoke(_Fn, _STD forward<_Args>(_Vals)...); } else { From 5b907b7639e31552c55bc8abaa4dd4b48cde4bdd Mon Sep 17 00:00:00 2001 From: achabense <60953653+achabense@users.noreply.github.com> Date: Thu, 14 Sep 2023 00:12:47 +0800 Subject: [PATCH 07/14] benchmark: vec_size 8000->10000 --- benchmarks/src/priority_queue_push_range.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/src/priority_queue_push_range.cpp b/benchmarks/src/priority_queue_push_range.cpp index 4c2406793d7..1dabe4e4fe9 100644 --- a/benchmarks/src/priority_queue_push_range.cpp +++ b/benchmarks/src/priority_queue_push_range.cpp @@ -11,7 +11,7 @@ using namespace std; namespace { - constexpr size_t vec_size = 8000; + constexpr size_t vec_size = 10000; template auto create_vec(size_t vsize, function transform) { From d5ffbe51ad808e14c51d0d257fead21b8b6c64e0 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 19 Sep 2023 20:39:22 -0700 Subject: [PATCH 08/14] Include more headers. --- benchmarks/src/priority_queue_push_range.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/benchmarks/src/priority_queue_push_range.cpp b/benchmarks/src/priority_queue_push_range.cpp index 1dabe4e4fe9..ee621a0010f 100644 --- a/benchmarks/src/priority_queue_push_range.cpp +++ b/benchmarks/src/priority_queue_push_range.cpp @@ -1,12 +1,17 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include #include +#include +#include +#include #include #include #include #include #include +#include #include using namespace std; From 6fe8eed96739c390ff4fa56fe03634144d402cd4 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 19 Sep 2023 20:41:02 -0700 Subject: [PATCH 09/14] `function transform` => `Fn transformation` --- benchmarks/src/priority_queue_push_range.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/benchmarks/src/priority_queue_push_range.cpp b/benchmarks/src/priority_queue_push_range.cpp index ee621a0010f..72fe85c79cb 100644 --- a/benchmarks/src/priority_queue_push_range.cpp +++ b/benchmarks/src/priority_queue_push_range.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -18,11 +17,11 @@ using namespace std; namespace { constexpr size_t vec_size = 10000; - template - auto create_vec(size_t vsize, function transform) { + template + auto create_vec(size_t vsize, Fn transformation) { vector vec(vsize); for (mt19937_64 rnd(1); auto& e : vec) { - e = transform(rnd()); + e = transformation(rnd()); } return vec; } From 28732aec6149fc15c8be7a58677865cb5a2204d9 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 19 Sep 2023 20:42:27 -0700 Subject: [PATCH 10/14] `create_vec` always takes `vec_size`. --- benchmarks/src/priority_queue_push_range.cpp | 22 +++++++++----------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/benchmarks/src/priority_queue_push_range.cpp b/benchmarks/src/priority_queue_push_range.cpp index 72fe85c79cb..563b35b0663 100644 --- a/benchmarks/src/priority_queue_push_range.cpp +++ b/benchmarks/src/priority_queue_push_range.cpp @@ -18,8 +18,8 @@ namespace { constexpr size_t vec_size = 10000; template - auto create_vec(size_t vsize, Fn transformation) { - vector vec(vsize); + auto create_vec(Fn transformation) { + vector vec(vec_size); for (mt19937_64 rnd(1); auto& e : vec) { e = transformation(rnd()); } @@ -31,17 +31,15 @@ namespace { return static_cast(val); } - const auto vec_u8 = create_vec(vec_size, cast_to); - const auto vec_u16 = create_vec(vec_size, cast_to); - const auto vec_u32 = create_vec(vec_size, cast_to); - const auto vec_u64 = create_vec(vec_size, cast_to); - const auto vec_float = create_vec(vec_size, cast_to); - const auto vec_double = create_vec(vec_size, cast_to); + const auto vec_u8 = create_vec(cast_to); + const auto vec_u16 = create_vec(cast_to); + const auto vec_u32 = create_vec(cast_to); + const auto vec_u64 = create_vec(cast_to); + const auto vec_float = create_vec(cast_to); + const auto vec_double = create_vec(cast_to); - const auto vec_str = - create_vec(vec_size, [](uint64_t val) { return to_string(static_cast(val)); }); - const auto vec_wstr = - create_vec(vec_size, [](uint64_t val) { return to_wstring(static_cast(val)); }); + const auto vec_str = create_vec([](uint64_t val) { return to_string(static_cast(val)); }); + const auto vec_wstr = create_vec([](uint64_t val) { return to_wstring(static_cast(val)); }); template void BM_push_range(benchmark::State& state) { From 234f0f3a5e25ff7ae25a01d13d54da9c9b9cb793 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 19 Sep 2023 20:42:53 -0700 Subject: [PATCH 11/14] Digit separator. --- benchmarks/src/priority_queue_push_range.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/src/priority_queue_push_range.cpp b/benchmarks/src/priority_queue_push_range.cpp index 563b35b0663..875c6e5c216 100644 --- a/benchmarks/src/priority_queue_push_range.cpp +++ b/benchmarks/src/priority_queue_push_range.cpp @@ -15,7 +15,7 @@ using namespace std; namespace { - constexpr size_t vec_size = 10000; + constexpr size_t vec_size = 10'000; template auto create_vec(Fn transformation) { From bef92863ad0a0707df4397f5f991b4293654e3c0 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 19 Sep 2023 20:43:27 -0700 Subject: [PATCH 12/14] `spn.subspan(0, take_size)` => `spn.first(take_size)` --- benchmarks/src/priority_queue_push_range.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/src/priority_queue_push_range.cpp b/benchmarks/src/priority_queue_push_range.cpp index 875c6e5c216..d2bf5e69cf9 100644 --- a/benchmarks/src/priority_queue_push_range.cpp +++ b/benchmarks/src/priority_queue_push_range.cpp @@ -51,7 +51,7 @@ namespace { while (!spn.empty()) { size_t take_size = min(spn.size(), frag_size); - que.push_range(spn.subspan(0, take_size)); + que.push_range(spn.first(take_size)); spn = spn.subspan(take_size); } benchmark::DoNotOptimize(que); From a66b992f7d4b830e9506b3a54977d8b39624afbf Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 19 Sep 2023 20:43:53 -0700 Subject: [PATCH 13/14] Mark `take_size` as `const`. --- benchmarks/src/priority_queue_push_range.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/src/priority_queue_push_range.cpp b/benchmarks/src/priority_queue_push_range.cpp index d2bf5e69cf9..444d2c2b30d 100644 --- a/benchmarks/src/priority_queue_push_range.cpp +++ b/benchmarks/src/priority_queue_push_range.cpp @@ -50,7 +50,7 @@ namespace { span spn{Data}; while (!spn.empty()) { - size_t take_size = min(spn.size(), frag_size); + const size_t take_size = min(spn.size(), frag_size); que.push_range(spn.first(take_size)); spn = spn.subspan(take_size); } From 9db2be448564af045576ab3105fddc24a0d13880 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 19 Sep 2023 20:46:14 -0700 Subject: [PATCH 14/14] Comment the threshold. --- stl/inc/queue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/queue b/stl/inc/queue index 58c61a980e4..201728b6235 100644 --- a/stl/inc/queue +++ b/stl/inc/queue @@ -391,7 +391,7 @@ public: } const size_type _New_size = c.size(); - if (_New_size / 2 > _Old_size) { + if (_New_size / 2 > _Old_size) { // threshold chosen for performance _Make_heap(); } else { const auto _Begin = _STD _Get_unwrapped(c.begin());