From 959f86e5f8c5db2effd7c8d889ccd19f0339ff6e Mon Sep 17 00:00:00 2001 From: anand76 Date: Wed, 20 Mar 2019 10:38:54 -0700 Subject: [PATCH] Use placement new and delete in autovector (#5080) Summary: The stack buffer in rocksdb::autovector is currently defined as an array of elements of the template type. This results in unnecessary construction of those objects, which can be a significant overhead in some cases. This PR changes the type of the stack buf to char* and uses placement new to construct new objects when they are inserted into the autovector. Pull Request resolved: https://github.com/facebook/rocksdb/pull/5080 Differential Revision: D14533221 Pulled By: anand1976 fbshipit-source-id: 9378985c7d03f4e1a28951bdd2403c72f10f23d7 --- util/autovector.h | 45 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/util/autovector.h b/util/autovector.h index 97348d818..5843fa8a1 100644 --- a/util/autovector.h +++ b/util/autovector.h @@ -179,15 +179,16 @@ class autovector { typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; - autovector() = default; + autovector() : values_(reinterpret_cast(buf_)) {} - autovector(std::initializer_list init_list) { + autovector(std::initializer_list init_list) + : values_(reinterpret_cast(buf_)) { for (const T& item : init_list) { push_back(item); } } - ~autovector() = default; + ~autovector() { clear(); } // -- Immutable operations // Indicate if all data resides in in-stack data structure. @@ -203,10 +204,18 @@ class autovector { void resize(size_type n) { if (n > kSize) { vect_.resize(n - kSize); + while (num_stack_items_ < kSize) { + new ((void*)(&values_[num_stack_items_++])) value_type(); + } num_stack_items_ = kSize; } else { vect_.clear(); - num_stack_items_ = n; + while (num_stack_items_ < n) { + new ((void*)(&values_[num_stack_items_++])) value_type(); + } + while (num_stack_items_ > n) { + values_[--num_stack_items_].~value_type(); + } } } @@ -214,12 +223,18 @@ class autovector { const_reference operator[](size_type n) const { assert(n < size()); - return n < kSize ? values_[n] : vect_[n - kSize]; + if (n < kSize) { + return values_[n]; + } + return vect_[n - kSize]; } reference operator[](size_type n) { assert(n < size()); - return n < kSize ? values_[n] : vect_[n - kSize]; + if (n < kSize) { + return values_[n]; + } + return vect_[n - kSize]; } const_reference at(size_type n) const { @@ -255,6 +270,7 @@ class autovector { // -- Mutable Operations void push_back(T&& item) { if (num_stack_items_ < kSize) { + new ((void*)(&values_[num_stack_items_])) value_type(); values_[num_stack_items_++] = std::move(item); } else { vect_.push_back(item); @@ -263,6 +279,7 @@ class autovector { void push_back(const T& item) { if (num_stack_items_ < kSize) { + new ((void*)(&values_[num_stack_items_])) value_type(); values_[num_stack_items_++] = item; } else { vect_.push_back(item); @@ -272,8 +289,8 @@ class autovector { template void emplace_back(Args&&... args) { if (num_stack_items_ < kSize) { - values_[num_stack_items_++] = - std::move(value_type(std::forward(args)...)); + new ((void*)(&values_[num_stack_items_++])) + value_type(std::forward(args)...); } else { vect_.emplace_back(std::forward(args)...); } @@ -284,12 +301,14 @@ class autovector { if (!vect_.empty()) { vect_.pop_back(); } else { - --num_stack_items_; + values_[--num_stack_items_].~value_type(); } } void clear() { - num_stack_items_ = 0; + while (num_stack_items_ > 0) { + values_[--num_stack_items_].~value_type(); + } vect_.clear(); } @@ -323,13 +342,17 @@ class autovector { private: size_type num_stack_items_ = 0; // current number of items - value_type values_[kSize]; // the first `kSize` items + alignas(alignof( + value_type)) char buf_[kSize * + sizeof(value_type)]; // the first `kSize` items + pointer values_; // used only if there are more than `kSize` items. std::vector vect_; }; template autovector& autovector::assign(const autovector& other) { + values_ = reinterpret_cast(buf_); // copy the internal vector vect_.assign(other.vect_.begin(), other.vect_.end());