diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index 2ea719861a19..480aa5c8d92c 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -13,7 +13,7 @@ bench_bench_pivx_SOURCES = \ bench/crypto_hash.cpp \ bench/perf.cpp \ bench/perf.h \ - bench/prevector_destructor.cpp + bench/prevector.cpp bench_bench_pivx_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/ bench_bench_pivx_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) diff --git a/src/bench/prevector.cpp b/src/bench/prevector.cpp new file mode 100644 index 000000000000..f192fc370ff6 --- /dev/null +++ b/src/bench/prevector.cpp @@ -0,0 +1,89 @@ +// Copyright (c) 2015-2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "bench/bench.h" + +#include "compat.h" +#include "prevector.h" +#include "serialize.h" +#include "streams.h" + +#include + +// GCC 4.8 is missing some C++11 type_traits, +// https://www.gnu.org/software/gcc/gcc-5/changes.html +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 +#define IS_TRIVIALLY_CONSTRUCTIBLE std::has_trivial_default_constructor +#else +#define IS_TRIVIALLY_CONSTRUCTIBLE std::is_trivially_default_constructible +#endif + +struct nontrivial_t { + int x; + nontrivial_t() :x(-1) {} +}; +static_assert(!IS_TRIVIALLY_CONSTRUCTIBLE::value, + "expected nontrivial_t to not be trivially constructible"); + +typedef unsigned char trivial_t; +static_assert(IS_TRIVIALLY_CONSTRUCTIBLE::value, + "expected trivial_t to be trivially constructible"); + +template +static void PrevectorDestructor(benchmark::State& state) +{ + while (state.KeepRunning()) { + for (auto x = 0; x < 1000; ++x) { + prevector<28, T> t0; + prevector<28, T> t1; + t0.resize(28); + t1.resize(29); + } + } +} + +template +static void PrevectorClear(benchmark::State& state) +{ + + while (state.KeepRunning()) { + for (auto x = 0; x < 1000; ++x) { + prevector<28, T> t0; + prevector<28, T> t1; + t0.resize(28); + t0.clear(); + t1.resize(29); + t0.clear(); + } + } +} + +template +void PrevectorResize(benchmark::State& state) +{ + while (state.KeepRunning()) { + prevector<28, T> t0; + prevector<28, T> t1; + for (auto x = 0; x < 1000; ++x) { + t0.resize(28); + t0.resize(0); + t1.resize(29); + t1.resize(0); + } + } +} + +#define PREVECTOR_TEST(name) \ + static void Prevector ## name ## Nontrivial(benchmark::State& state) { \ + PrevectorResize(state); \ + } \ + BENCHMARK(Prevector ## name ## Nontrivial); \ + static void Prevector ## name ## Trivial(benchmark::State& state) { \ + PrevectorResize(state); \ + } \ + BENCHMARK(Prevector ## name ## Trivial); + +PREVECTOR_TEST(Clear) +PREVECTOR_TEST(Destructor) +PREVECTOR_TEST(Resize) diff --git a/src/bench/prevector_destructor.cpp b/src/bench/prevector_destructor.cpp deleted file mode 100644 index aa178e6ad404..000000000000 --- a/src/bench/prevector_destructor.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2015-2017 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "bench.h" -#include "prevector.h" - -static void PrevectorDestructor(benchmark::State& state) -{ - while (state.KeepRunning()) { - for (auto x = 0; x < 1000; ++x) { - prevector<28, unsigned char> t0; - prevector<28, unsigned char> t1; - t0.resize(28); - t1.resize(29); - } - } -} - -static void PrevectorClear(benchmark::State& state) -{ - - while (state.KeepRunning()) { - for (auto x = 0; x < 1000; ++x) { - prevector<28, unsigned char> t0; - prevector<28, unsigned char> t1; - t0.resize(28); - t0.clear(); - t1.resize(29); - t0.clear(); - } - } -} - -BENCHMARK(PrevectorDestructor); -BENCHMARK(PrevectorClear); \ No newline at end of file diff --git a/src/prevector.h b/src/prevector.h index 14aa1ea8c9a2..f3294870b46f 100644 --- a/src/prevector.h +++ b/src/prevector.h @@ -10,6 +10,8 @@ #include #include +#include +#include #include #include @@ -194,16 +196,27 @@ class prevector { T* item_ptr(difference_type pos) { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); } const T* item_ptr(difference_type pos) const { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); } + void fill(T* dst, ptrdiff_t count, const T& value = T{}) { + std::fill_n(dst, count, value); + } + + template + void fill(T* dst, InputIterator first, InputIterator last) { + while (first != last) { + new(static_cast(dst)) T(*first); + ++dst; + ++first; + } + } + public: void assign(size_type n, const T& val) { clear(); if (capacity() < n) { change_capacity(n); } - while (size() < n) { - _size++; - new(static_cast(item_ptr(size() - 1))) T(val); - } + _size += n; + fill(item_ptr(0), n, val); } template @@ -213,11 +226,8 @@ class prevector { if (capacity() < n) { change_capacity(n); } - while (first != last) { - _size++; - new(static_cast(item_ptr(size() - 1))) T(*first); - ++first; - } + _size += n; + fill(item_ptr(0), first, last); } prevector() {} @@ -228,31 +238,23 @@ class prevector { explicit prevector(size_type n, const T& val = T()) { change_capacity(n); - while (size() < n) { - _size++; - new(static_cast(item_ptr(size() - 1))) T(val); - } + _size += n; + fill(item_ptr(0), n, val); } template prevector(InputIterator first, InputIterator last) { size_type n = last - first; change_capacity(n); - while (first != last) { - _size++; - new(static_cast(item_ptr(size() - 1))) T(*first); - ++first; - } + _size += n; + fill(item_ptr(0), first, last); } prevector(const prevector& other) { - change_capacity(other.size()); - const_iterator it = other.begin(); - while (it != other.end()) { - _size++; - new(static_cast(item_ptr(size() - 1))) T(*it); - ++it; - } + size_type n = other.size(); + change_capacity(n); + _size += n; + fill(item_ptr(0), other.begin(), other.end()); } prevector(prevector&& other) { @@ -263,14 +265,7 @@ class prevector { if (&other == this) { return *this; } - resize(0); - change_capacity(other.size()); - const_iterator it = other.begin(); - while (it != other.end()) { - _size++; - new(static_cast(item_ptr(size() - 1))) T(*it); - ++it; - } + assign(other.begin(), other.end()); return *this; } @@ -314,16 +309,20 @@ class prevector { } void resize(size_type new_size) { - if (size() > new_size) { + size_type cur_size = size(); + if (cur_size == new_size) { + return; + } + if (cur_size > new_size) { erase(item_ptr(new_size), end()); + return; } if (new_size > capacity()) { change_capacity(new_size); } - while (size() < new_size) { - _size++; - new(static_cast(item_ptr(size() - 1))) T(); - } + ptrdiff_t increase = new_size - cur_size; + fill(item_ptr(cur_size), increase); + _size += increase; } void reserve(size_type new_capacity) { @@ -346,10 +345,11 @@ class prevector { if (capacity() < new_size) { change_capacity(new_size + (new_size >> 1)); } - memmove(item_ptr(p + 1), item_ptr(p), (size() - p) * sizeof(T)); + T* ptr = item_ptr(p); + memmove(ptr + 1, ptr, (size() - p) * sizeof(T)); _size++; - new(static_cast(item_ptr(p))) T(value); - return iterator(item_ptr(p)); + new(static_cast(ptr)) T(value); + return iterator(ptr); } void insert(iterator pos, size_type count, const T& value) { @@ -358,11 +358,10 @@ class prevector { if (capacity() < new_size) { change_capacity(new_size + (new_size >> 1)); } - memmove(item_ptr(p + count), item_ptr(p), (size() - p) * sizeof(T)); + T* ptr = item_ptr(p); + memmove(ptr + count, ptr, (size() - p) * sizeof(T)); _size += count; - for (size_type i = 0; i < count; i++) { - new(static_cast(item_ptr(p + i))) T(value); - } + fill(item_ptr(p), count, value); } template