diff options
Diffstat (limited to 'absl/container/inlined_vector_benchmark.cc')
-rw-r--r-- | absl/container/inlined_vector_benchmark.cc | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/absl/container/inlined_vector_benchmark.cc b/absl/container/inlined_vector_benchmark.cc new file mode 100644 index 00000000..a2035e35 --- /dev/null +++ b/absl/container/inlined_vector_benchmark.cc @@ -0,0 +1,376 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/container/inlined_vector.h" + +#include <string> +#include <vector> + +#include "absl/base/internal/raw_logging.h" +#include "absl/strings/str_cat.h" +#include "benchmark/benchmark.h" + +namespace { + +using IntVec = absl::InlinedVector<int, 8>; + +void BM_InlinedVectorFill(benchmark::State& state) { + const int len = state.range(0); + for (auto _ : state) { + IntVec v; + for (int i = 0; i < len; i++) { + v.push_back(i); + } + } + state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len); +} +BENCHMARK(BM_InlinedVectorFill)->Range(0, 1024); + +void BM_InlinedVectorFillRange(benchmark::State& state) { + const int len = state.range(0); + std::unique_ptr<int[]> ia(new int[len]); + for (int i = 0; i < len; i++) { + ia[i] = i; + } + for (auto _ : state) { + IntVec v(ia.get(), ia.get() + len); + benchmark::DoNotOptimize(v); + } + state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len); +} +BENCHMARK(BM_InlinedVectorFillRange)->Range(0, 1024); + +void BM_StdVectorFill(benchmark::State& state) { + const int len = state.range(0); + for (auto _ : state) { + std::vector<int> v; + for (int i = 0; i < len; i++) { + v.push_back(i); + } + } + state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len); +} +BENCHMARK(BM_StdVectorFill)->Range(0, 1024); + +bool StringRepresentedInline(std::string s) { + const char* chars = s.data(); + std::string s1 = std::move(s); + return s1.data() != chars; +} + +void BM_InlinedVectorFillString(benchmark::State& state) { + const int len = state.range(0); + std::string strings[4] = {"a quite long string", + "another long string", + "012345678901234567", + "to cause allocation"}; + for (auto _ : state) { + absl::InlinedVector<std::string, 8> v; + for (int i = 0; i < len; i++) { + v.push_back(strings[i & 3]); + } + } + state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len); +} +BENCHMARK(BM_InlinedVectorFillString)->Range(0, 1024); + +void BM_StdVectorFillString(benchmark::State& state) { + const int len = state.range(0); + std::string strings[4] = {"a quite long string", + "another long string", + "012345678901234567", + "to cause allocation"}; + for (auto _ : state) { + std::vector<std::string> v; + for (int i = 0; i < len; i++) { + v.push_back(strings[i & 3]); + } + } + state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len); + // The purpose of the benchmark is to verify that inlined vector is + // efficient when moving is more efficent than copying. To do so, we + // use strings that are larger than the small std::string optimization. + ABSL_RAW_CHECK(!StringRepresentedInline(strings[0]), + "benchmarked with strings that are too small"); +} +BENCHMARK(BM_StdVectorFillString)->Range(0, 1024); + +struct Buffer { // some arbitrary structure for benchmarking. + char* base; + int length; + int capacity; + void* user_data; +}; + +void BM_InlinedVectorTenAssignments(benchmark::State& state) { + const int len = state.range(0); + using BufferVec = absl::InlinedVector<Buffer, 2>; + + BufferVec src; + src.resize(len); + + BufferVec dst; + for (auto _ : state) { + for (int i = 0; i < 10; ++i) { + dst = src; + } + } +} +BENCHMARK(BM_InlinedVectorTenAssignments) + ->Arg(0)->Arg(1)->Arg(2)->Arg(3)->Arg(4)->Arg(20); + +void BM_CreateFromContainer(benchmark::State& state) { + for (auto _ : state) { + absl::InlinedVector<int, 4> x(absl::InlinedVector<int, 4>{1, 2, 3}); + benchmark::DoNotOptimize(x); + } +} +BENCHMARK(BM_CreateFromContainer); + +struct LargeCopyableOnly { + LargeCopyableOnly() : d(1024, 17) {} + LargeCopyableOnly(const LargeCopyableOnly& o) = default; + LargeCopyableOnly& operator=(const LargeCopyableOnly& o) = default; + + std::vector<int> d; +}; + +struct LargeCopyableSwappable { + LargeCopyableSwappable() : d(1024, 17) {} + LargeCopyableSwappable(const LargeCopyableSwappable& o) = default; + LargeCopyableSwappable(LargeCopyableSwappable&& o) = delete; + + LargeCopyableSwappable& operator=(LargeCopyableSwappable o) { + using std::swap; + swap(*this, o); + return *this; + } + LargeCopyableSwappable& operator=(LargeCopyableSwappable&& o) = delete; + + friend void swap(LargeCopyableSwappable& a, LargeCopyableSwappable& b) { + using std::swap; + swap(a.d, b.d); + } + + std::vector<int> d; +}; + +struct LargeCopyableMovable { + LargeCopyableMovable() : d(1024, 17) {} + // Use implicitly defined copy and move. + + std::vector<int> d; +}; + +struct LargeCopyableMovableSwappable { + LargeCopyableMovableSwappable() : d(1024, 17) {} + LargeCopyableMovableSwappable(const LargeCopyableMovableSwappable& o) = + default; + LargeCopyableMovableSwappable(LargeCopyableMovableSwappable&& o) = default; + + LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable o) { + using std::swap; + swap(*this, o); + return *this; + } + LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable&& o) = + default; + + friend void swap(LargeCopyableMovableSwappable& a, + LargeCopyableMovableSwappable& b) { + using std::swap; + swap(a.d, b.d); + } + + std::vector<int> d; +}; + +template <typename ElementType> +void BM_SwapElements(benchmark::State& state) { + const int len = state.range(0); + using Vec = absl::InlinedVector<ElementType, 32>; + Vec a(len); + Vec b; + for (auto _ : state) { + using std::swap; + swap(a, b); + } +} +BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableOnly)->Range(0, 1024); +BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableSwappable)->Range(0, 1024); +BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovable)->Range(0, 1024); +BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovableSwappable) + ->Range(0, 1024); + +// The following benchmark is meant to track the efficiency of the vector size +// as a function of stored type via the benchmark label. It is not meant to +// output useful sizeof operator performance. The loop is a dummy operation +// to fulfill the requirement of running the benchmark. +template <typename VecType> +void BM_Sizeof(benchmark::State& state) { + int size = 0; + for (auto _ : state) { + VecType vec; + size = sizeof(vec); + } + state.SetLabel(absl::StrCat("sz=", size)); +} +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 1>); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 4>); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 7>); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 8>); + +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 1>); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 4>); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 7>); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 8>); + +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 1>); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 4>); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 7>); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 8>); + +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 1>); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 4>); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 7>); +BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 8>); + +void BM_InlinedVectorIndexInlined(benchmark::State& state) { + absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7}; + for (auto _ : state) { + for (int i = 0; i < 1000; ++i) { + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v[4]); + } + } + state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations())); +} +BENCHMARK(BM_InlinedVectorIndexInlined); + +void BM_InlinedVectorIndexExternal(benchmark::State& state) { + absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + for (auto _ : state) { + for (int i = 0; i < 1000; ++i) { + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v[4]); + } + } + state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations())); +} +BENCHMARK(BM_InlinedVectorIndexExternal); + +void BM_StdVectorIndex(benchmark::State& state) { + std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + for (auto _ : state) { + for (int i = 0; i < 1000; ++i) { + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(v[4]); + } + } + state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations())); +} +BENCHMARK(BM_StdVectorIndex); + +#define UNROLL_2(x) \ + benchmark::DoNotOptimize(x); \ + benchmark::DoNotOptimize(x); + +#define UNROLL_4(x) UNROLL_2(x) UNROLL_2(x) +#define UNROLL_8(x) UNROLL_4(x) UNROLL_4(x) +#define UNROLL_16(x) UNROLL_8(x) UNROLL_8(x); + +void BM_InlinedVectorDataInlined(benchmark::State& state) { + absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7}; + for (auto _ : state) { + UNROLL_16(v.data()); + } + state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); +} +BENCHMARK(BM_InlinedVectorDataInlined); + +void BM_InlinedVectorDataExternal(benchmark::State& state) { + absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + for (auto _ : state) { + UNROLL_16(v.data()); + } + state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); +} +BENCHMARK(BM_InlinedVectorDataExternal); + +void BM_StdVectorData(benchmark::State& state) { + std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + for (auto _ : state) { + UNROLL_16(v.data()); + } + state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); +} +BENCHMARK(BM_StdVectorData); + +void BM_InlinedVectorSizeInlined(benchmark::State& state) { + absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7}; + for (auto _ : state) { + UNROLL_16(v.size()); + } + state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); +} +BENCHMARK(BM_InlinedVectorSizeInlined); + +void BM_InlinedVectorSizeExternal(benchmark::State& state) { + absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + for (auto _ : state) { + UNROLL_16(v.size()); + } + state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); +} +BENCHMARK(BM_InlinedVectorSizeExternal); + +void BM_StdVectorSize(benchmark::State& state) { + std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + for (auto _ : state) { + UNROLL_16(v.size()); + } + state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); +} +BENCHMARK(BM_StdVectorSize); + +void BM_InlinedVectorEmptyInlined(benchmark::State& state) { + absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7}; + for (auto _ : state) { + UNROLL_16(v.empty()); + } + state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); +} +BENCHMARK(BM_InlinedVectorEmptyInlined); + +void BM_InlinedVectorEmptyExternal(benchmark::State& state) { + absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + for (auto _ : state) { + UNROLL_16(v.empty()); + } + state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); +} +BENCHMARK(BM_InlinedVectorEmptyExternal); + +void BM_StdVectorEmpty(benchmark::State& state) { + std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + for (auto _ : state) { + UNROLL_16(v.empty()); + } + state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); +} +BENCHMARK(BM_StdVectorEmpty); + +} // namespace + +BENCHMARK_MAIN(); |