From: Jonathan Wakely Date: Thu, 15 Nov 2018 00:04:19 +0000 (+0000) Subject: Optimize pool resource allocation X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a15032ee7bce189634618226975ebf33a4e8e7aa;p=gcc.git Optimize pool resource allocation A recent change caused a performance regression. This restores the previous performance and adds a performance test. * scripts/check_performance: Allow tests to choose a -std flag. * src/c++17/memory_resource.cc (bitset::get_first_unset()): Use local variables of the right types. Call update_next_word() unconditionally. * testsuite/20_util/unsynchronized_pool_resource/cons.cc: New test. * testsuite/performance/20_util/memory_resource/pools.cc: New test. * testsuite/util/testsuite_performance.h (time_counter): Allow timer to be restarted. From-SVN: r266164 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 5262ef54782..85e79eae8b2 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,13 @@ 2018-11-15 Jonathan Wakely + * scripts/check_performance: Allow tests to choose a -std flag. + * src/c++17/memory_resource.cc (bitset::get_first_unset()): Use local + variables of the right types. Call update_next_word() unconditionally. + * testsuite/20_util/unsynchronized_pool_resource/cons.cc: New test. + * testsuite/performance/20_util/memory_resource/pools.cc: New test. + * testsuite/util/testsuite_performance.h (time_counter): Allow + timer to be restarted. + * testsuite/20_util/unsynchronized_pool_resource/allocate.cc: Fix test for 32-bit targets. Test additional allocation sizes. diff --git a/libstdc++-v3/scripts/check_performance b/libstdc++-v3/scripts/check_performance index d196355bd44..3fa927480c9 100755 --- a/libstdc++-v3/scripts/check_performance +++ b/libstdc++-v3/scripts/check_performance @@ -44,6 +44,8 @@ do TESTNAME=$SRC_DIR/testsuite/$NAME FILE_NAME="`basename $NAME`" FILE_NAME="`echo $FILE_NAME | sed 's/.cc//g'`" + ORIG_CXX="$CXX" + CXX="$CXX `sed -n 's/.* STD=/-std=/p' $TESTNAME`" # TEST_S == single thread # TEST_B == do both single and multi-thread @@ -90,6 +92,7 @@ do mv tmp.$FILE_NAME $FILE_NAME.xml fi fi + CXX="$ORIG_CXX" done exit 0 diff --git a/libstdc++-v3/src/c++17/memory_resource.cc b/libstdc++-v3/src/c++17/memory_resource.cc index 605bdd53950..79c1665146d 100644 --- a/libstdc++-v3/src/c++17/memory_resource.cc +++ b/libstdc++-v3/src/c++17/memory_resource.cc @@ -335,17 +335,16 @@ namespace pmr size_type get_first_unset() noexcept { - if (_M_next_word < nwords()) + const size_type wd = _M_next_word; + if (wd < nwords()) { - const size_type n = std::__countr_one(_M_words[_M_next_word]); + const size_type n = std::__countr_one(_M_words[wd]); if (n < bits_per_word) { const word bit = word(1) << n; - _M_words[_M_next_word] |= bit; - const size_t res = (_M_next_word * bits_per_word) + n; - if (n == (bits_per_word - 1)) - update_next_word(); - return res; + _M_words[wd] |= bit; + update_next_word(); + return (wd * bits_per_word) + n; } } return size_type(-1); diff --git a/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/cons.cc b/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/cons.cc new file mode 100644 index 00000000000..14519ba1d00 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/unsynchronized_pool_resource/cons.cc @@ -0,0 +1,80 @@ +// Copyright (C) 2018 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++17" } +// { dg-do run { target c++17 } } + +#include +#include +#include + +void +test01() +{ + __gnu_test::memory_resource test_mr1, test_mr2; + __gnu_test::default_resource_mgr mgr(&test_mr1); + + const std::pmr::pool_options opts{1, 2}; + using std::pmr::unsynchronized_pool_resource; + + unsynchronized_pool_resource p1 = {opts, &test_mr2}; + VERIFY( p1.upstream_resource() == &test_mr2 ); + unsynchronized_pool_resource p2; + VERIFY( p2.upstream_resource() == std::pmr::get_default_resource() ); + unsynchronized_pool_resource p3{&test_mr2}; + VERIFY( p3.upstream_resource() == &test_mr2 ); + unsynchronized_pool_resource p4{opts}; + VERIFY( p4.upstream_resource() == std::pmr::get_default_resource() ); + + static_assert(!std::is_copy_constructible_v); + static_assert(!std::is_copy_assignable_v); + static_assert(std::is_destructible_v); +} + +void +test02() +{ + __gnu_test::memory_resource test_mr1, test_mr2; + __gnu_test::default_resource_mgr mgr(&test_mr1); + + const std::pmr::pool_options opts{1, 2}; + + struct derived : std::pmr::unsynchronized_pool_resource + { + using unsynchronized_pool_resource::unsynchronized_pool_resource; + }; + + derived p1 = {opts, &test_mr2}; + VERIFY( p1.upstream_resource() == &test_mr2 ); + derived p2; + VERIFY( p2.upstream_resource() == std::pmr::get_default_resource() ); + derived p3{&test_mr2}; + VERIFY( p3.upstream_resource() == &test_mr2 ); + derived p4{opts}; + VERIFY( p4.upstream_resource() == std::pmr::get_default_resource() ); + + static_assert(!std::is_copy_constructible_v); + static_assert(!std::is_copy_assignable_v); + static_assert(std::is_destructible_v); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/performance/20_util/memory_resource/pools.cc b/libstdc++-v3/testsuite/performance/20_util/memory_resource/pools.cc new file mode 100644 index 00000000000..77f37fe63b2 --- /dev/null +++ b/libstdc++-v3/testsuite/performance/20_util/memory_resource/pools.cc @@ -0,0 +1,114 @@ +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// Override the -std flag in the check_performance script: STD=gnu++17 + +#include +#include +#include +#include + +struct size16 { char c[16]; }; +struct size32 { char c[32]; }; +struct size64 { char c[64]; }; +struct size128 { char c[128]; }; + +// Insert and remove elements of various sizes in std::list containers. +// If report=true the function will measure and report the total performance +// including the time taken to destroy the lists and deallocate everything. +// If dest=false the function will measure and report the performance of +// insert/remove operations only, not the destruction of the lists. +void +populate_lists(std::pmr::memory_resource* r, std::string name, bool dest, + int kmax = 100) +{ + name += " std::list push/pop"; + if (dest) + name += "/destroy"; + + std::pmr::list l4(r); + std::pmr::list l16(r); + std::pmr::list l32(r); + std::pmr::list l64(r); + std::pmr::list l128(r); + + using namespace __gnu_test; + time_counter time; + resource_counter resource; + start_counters(time, resource); + + const int imax = 1000; + const int jmax = 100; + for (int k = 0; k < kmax; ++k) + { + for (int i = 0; i < imax; ++i) + { + for (int j = 0; j < jmax; ++j) + { + l4.emplace_back(); + l16.emplace_back(); + l32.emplace_back(); + l64.emplace_back(); + l128.emplace_back(); + } + l4.pop_front(); + l16.pop_front(); + l32.pop_front(); + l64.pop_front(); + l128.pop_front(); + } + + if (!dest) + time.stop(); + + // Deallocate everything: + l4.clear(); + l16.clear(); + l32.clear(); + l64.clear(); + l128.clear(); + + if (!dest) + time.restart(); + } + + stop_counters(time, resource); + + report_performance(__FILE__, name.c_str(), time, resource); + clear_counters(time, resource); +} + +int main() +{ + std::pmr::memory_resource* newdel = std::pmr::new_delete_resource(); + std::pmr::unsynchronized_pool_resource pool; + + for (auto b : { false, true }) + { + // Start with an empty set of pools: + pool.release(); + + populate_lists(newdel, "new_delete 1", b); + populate_lists(newdel, "new_delete 2", b); + populate_lists(newdel, "new_delete 3", b); + + populate_lists(&pool, "unsync pool 1", b); + // Destroy pools and start fresh: + pool.release(); + populate_lists(&pool, "unsync pool 2", b); + // Do not destroy pools, reuse allocated memory: + populate_lists(&pool, "unsync pool 3", b); + } +} diff --git a/libstdc++-v3/testsuite/util/testsuite_performance.h b/libstdc++-v3/testsuite/util/testsuite_performance.h index 3dfd471221d..38ec35d4c45 100644 --- a/libstdc++-v3/testsuite/util/testsuite_performance.h +++ b/libstdc++-v3/testsuite/util/testsuite_performance.h @@ -79,10 +79,12 @@ namespace __gnu_test clock_t elapsed_end; tms tms_begin; tms tms_end; + std::size_t splits[3]; public: explicit - time_counter() : elapsed_begin(), elapsed_end(), tms_begin(), tms_end() + time_counter() + : elapsed_begin(), elapsed_end(), tms_begin(), tms_end(), splits() { } void @@ -92,6 +94,7 @@ namespace __gnu_test elapsed_end = clock_t(); tms_begin = tms(); tms_end = tms(); + splits[0] = splits[1] = splits[2] = 0; } void @@ -113,17 +116,29 @@ namespace __gnu_test std::__throw_runtime_error("time_counter::stop"); } + void + restart() + { + splits[0] += (elapsed_end - elapsed_begin); + splits[1] += (tms_end.tms_utime - tms_begin.tms_utime); + splits[2] += (tms_end.tms_stime - tms_begin.tms_stime); + elapsed_begin = times(&tms_begin); + const clock_t err = clock_t(-1); + if (elapsed_begin == err) + std::__throw_runtime_error("time_counter::restart"); + } + std::size_t real_time() const - { return elapsed_end - elapsed_begin; } + { return (elapsed_end - elapsed_begin) + splits[0]; } std::size_t user_time() const - { return tms_end.tms_utime - tms_begin.tms_utime; } + { return (tms_end.tms_utime - tms_begin.tms_utime) + splits[1]; } std::size_t system_time() const - { return tms_end.tms_stime - tms_begin.tms_stime; } + { return (tms_end.tms_stime - tms_begin.tms_stime) + splits[1]; } }; class resource_counter