inlined_vector_benchmark.cc
Go to the documentation of this file.
00001 // Copyright 2019 The Abseil Authors.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //      https://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 
00015 #include <string>
00016 #include <vector>
00017 
00018 #include "benchmark/benchmark.h"
00019 #include "absl/base/internal/raw_logging.h"
00020 #include "absl/base/macros.h"
00021 #include "absl/container/inlined_vector.h"
00022 #include "absl/strings/str_cat.h"
00023 
00024 namespace {
00025 
00026 void BM_InlinedVectorFill(benchmark::State& state) {
00027   absl::InlinedVector<int, 8> v;
00028   int val = 10;
00029   for (auto _ : state) {
00030     benchmark::DoNotOptimize(v);
00031     v.push_back(val);
00032   }
00033 }
00034 BENCHMARK(BM_InlinedVectorFill)->Range(0, 1024);
00035 
00036 void BM_InlinedVectorFillRange(benchmark::State& state) {
00037   const int len = state.range(0);
00038   std::unique_ptr<int[]> ia(new int[len]);
00039   for (int i = 0; i < len; i++) {
00040     ia[i] = i;
00041   }
00042   auto* from = ia.get();
00043   auto* to = from + len;
00044   for (auto _ : state) {
00045     benchmark::DoNotOptimize(from);
00046     benchmark::DoNotOptimize(to);
00047     absl::InlinedVector<int, 8> v(from, to);
00048     benchmark::DoNotOptimize(v);
00049   }
00050 }
00051 BENCHMARK(BM_InlinedVectorFillRange)->Range(0, 1024);
00052 
00053 void BM_StdVectorFill(benchmark::State& state) {
00054   std::vector<int> v;
00055   int val = 10;
00056   for (auto _ : state) {
00057     benchmark::DoNotOptimize(v);
00058     benchmark::DoNotOptimize(val);
00059     v.push_back(val);
00060   }
00061 }
00062 BENCHMARK(BM_StdVectorFill)->Range(0, 1024);
00063 
00064 // The purpose of the next two benchmarks is to verify that
00065 // absl::InlinedVector is efficient when moving is more efficent than
00066 // copying. To do so, we use strings that are larger than the short
00067 // string optimization.
00068 bool StringRepresentedInline(std::string s) {
00069   const char* chars = s.data();
00070   std::string s1 = std::move(s);
00071   return s1.data() != chars;
00072 }
00073 
00074 int GetNonShortStringOptimizationSize() {
00075   for (int i = 24; i <= 192; i *= 2) {
00076     if (!StringRepresentedInline(std::string(i, 'A'))) {
00077       return i;
00078     }
00079   }
00080   ABSL_RAW_LOG(
00081       FATAL,
00082       "Failed to find a std::string larger than the short std::string optimization");
00083   return -1;
00084 }
00085 
00086 void BM_InlinedVectorFillString(benchmark::State& state) {
00087   const int len = state.range(0);
00088   const int no_sso = GetNonShortStringOptimizationSize();
00089   std::string strings[4] = {std::string(no_sso, 'A'), std::string(no_sso, 'B'),
00090                             std::string(no_sso, 'C'), std::string(no_sso, 'D')};
00091 
00092   for (auto _ : state) {
00093     absl::InlinedVector<std::string, 8> v;
00094     for (int i = 0; i < len; i++) {
00095       v.push_back(strings[i & 3]);
00096     }
00097   }
00098   state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
00099 }
00100 BENCHMARK(BM_InlinedVectorFillString)->Range(0, 1024);
00101 
00102 void BM_StdVectorFillString(benchmark::State& state) {
00103   const int len = state.range(0);
00104   const int no_sso = GetNonShortStringOptimizationSize();
00105   std::string strings[4] = {std::string(no_sso, 'A'), std::string(no_sso, 'B'),
00106                             std::string(no_sso, 'C'), std::string(no_sso, 'D')};
00107 
00108   for (auto _ : state) {
00109     std::vector<std::string> v;
00110     for (int i = 0; i < len; i++) {
00111       v.push_back(strings[i & 3]);
00112     }
00113   }
00114   state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len);
00115 }
00116 BENCHMARK(BM_StdVectorFillString)->Range(0, 1024);
00117 
00118 struct Buffer {  // some arbitrary structure for benchmarking.
00119   char* base;
00120   int length;
00121   int capacity;
00122   void* user_data;
00123 };
00124 
00125 void BM_InlinedVectorAssignments(benchmark::State& state) {
00126   const int len = state.range(0);
00127   using BufferVec = absl::InlinedVector<Buffer, 2>;
00128 
00129   BufferVec src;
00130   src.resize(len);
00131 
00132   BufferVec dst;
00133   for (auto _ : state) {
00134     benchmark::DoNotOptimize(dst);
00135     benchmark::DoNotOptimize(src);
00136     dst = src;
00137   }
00138 }
00139 BENCHMARK(BM_InlinedVectorAssignments)
00140     ->Arg(0)
00141     ->Arg(1)
00142     ->Arg(2)
00143     ->Arg(3)
00144     ->Arg(4)
00145     ->Arg(20);
00146 
00147 void BM_CreateFromContainer(benchmark::State& state) {
00148   for (auto _ : state) {
00149     absl::InlinedVector<int, 4> src{1, 2, 3};
00150     benchmark::DoNotOptimize(src);
00151     absl::InlinedVector<int, 4> dst(std::move(src));
00152     benchmark::DoNotOptimize(dst);
00153   }
00154 }
00155 BENCHMARK(BM_CreateFromContainer);
00156 
00157 struct LargeCopyableOnly {
00158   LargeCopyableOnly() : d(1024, 17) {}
00159   LargeCopyableOnly(const LargeCopyableOnly& o) = default;
00160   LargeCopyableOnly& operator=(const LargeCopyableOnly& o) = default;
00161 
00162   std::vector<int> d;
00163 };
00164 
00165 struct LargeCopyableSwappable {
00166   LargeCopyableSwappable() : d(1024, 17) {}
00167 
00168   LargeCopyableSwappable(const LargeCopyableSwappable& o) = default;
00169 
00170   LargeCopyableSwappable& operator=(LargeCopyableSwappable o) {
00171     using std::swap;
00172     swap(*this, o);
00173     return *this;
00174   }
00175 
00176   friend void swap(LargeCopyableSwappable& a, LargeCopyableSwappable& b) {
00177     using std::swap;
00178     swap(a.d, b.d);
00179   }
00180 
00181   std::vector<int> d;
00182 };
00183 
00184 struct LargeCopyableMovable {
00185   LargeCopyableMovable() : d(1024, 17) {}
00186   // Use implicitly defined copy and move.
00187 
00188   std::vector<int> d;
00189 };
00190 
00191 struct LargeCopyableMovableSwappable {
00192   LargeCopyableMovableSwappable() : d(1024, 17) {}
00193   LargeCopyableMovableSwappable(const LargeCopyableMovableSwappable& o) =
00194       default;
00195   LargeCopyableMovableSwappable(LargeCopyableMovableSwappable&& o) = default;
00196 
00197   LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable o) {
00198     using std::swap;
00199     swap(*this, o);
00200     return *this;
00201   }
00202   LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable&& o) =
00203       default;
00204 
00205   friend void swap(LargeCopyableMovableSwappable& a,
00206                    LargeCopyableMovableSwappable& b) {
00207     using std::swap;
00208     swap(a.d, b.d);
00209   }
00210 
00211   std::vector<int> d;
00212 };
00213 
00214 template <typename ElementType>
00215 void BM_SwapElements(benchmark::State& state) {
00216   const int len = state.range(0);
00217   using Vec = absl::InlinedVector<ElementType, 32>;
00218   Vec a(len);
00219   Vec b;
00220   for (auto _ : state) {
00221     using std::swap;
00222     benchmark::DoNotOptimize(a);
00223     benchmark::DoNotOptimize(b);
00224     swap(a, b);
00225   }
00226 }
00227 BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableOnly)->Range(0, 1024);
00228 BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableSwappable)->Range(0, 1024);
00229 BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovable)->Range(0, 1024);
00230 BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovableSwappable)
00231     ->Range(0, 1024);
00232 
00233 // The following benchmark is meant to track the efficiency of the vector size
00234 // as a function of stored type via the benchmark label. It is not meant to
00235 // output useful sizeof operator performance. The loop is a dummy operation
00236 // to fulfill the requirement of running the benchmark.
00237 template <typename VecType>
00238 void BM_Sizeof(benchmark::State& state) {
00239   int size = 0;
00240   for (auto _ : state) {
00241     VecType vec;
00242     size = sizeof(vec);
00243   }
00244   state.SetLabel(absl::StrCat("sz=", size));
00245 }
00246 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 1>);
00247 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 4>);
00248 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 7>);
00249 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 8>);
00250 
00251 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 1>);
00252 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 4>);
00253 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 7>);
00254 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 8>);
00255 
00256 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 1>);
00257 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 4>);
00258 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 7>);
00259 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 8>);
00260 
00261 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 1>);
00262 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 4>);
00263 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 7>);
00264 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 8>);
00265 
00266 void BM_InlinedVectorIndexInlined(benchmark::State& state) {
00267   absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
00268   for (auto _ : state) {
00269     benchmark::DoNotOptimize(v);
00270     benchmark::DoNotOptimize(v[4]);
00271   }
00272 }
00273 BENCHMARK(BM_InlinedVectorIndexInlined);
00274 
00275 void BM_InlinedVectorIndexExternal(benchmark::State& state) {
00276   absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
00277   for (auto _ : state) {
00278     benchmark::DoNotOptimize(v);
00279     benchmark::DoNotOptimize(v[4]);
00280   }
00281 }
00282 BENCHMARK(BM_InlinedVectorIndexExternal);
00283 
00284 void BM_StdVectorIndex(benchmark::State& state) {
00285   std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
00286   for (auto _ : state) {
00287     benchmark::DoNotOptimize(v);
00288     benchmark::DoNotOptimize(v[4]);
00289   }
00290 }
00291 BENCHMARK(BM_StdVectorIndex);
00292 
00293 void BM_InlinedVectorDataInlined(benchmark::State& state) {
00294   absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
00295   for (auto _ : state) {
00296     benchmark::DoNotOptimize(v);
00297     benchmark::DoNotOptimize(v.data());
00298   }
00299 }
00300 BENCHMARK(BM_InlinedVectorDataInlined);
00301 
00302 void BM_InlinedVectorDataExternal(benchmark::State& state) {
00303   absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
00304   for (auto _ : state) {
00305     benchmark::DoNotOptimize(v);
00306     benchmark::DoNotOptimize(v.data());
00307   }
00308   state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
00309 }
00310 BENCHMARK(BM_InlinedVectorDataExternal);
00311 
00312 void BM_StdVectorData(benchmark::State& state) {
00313   std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
00314   for (auto _ : state) {
00315     benchmark::DoNotOptimize(v);
00316     benchmark::DoNotOptimize(v.data());
00317   }
00318   state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations()));
00319 }
00320 BENCHMARK(BM_StdVectorData);
00321 
00322 void BM_InlinedVectorSizeInlined(benchmark::State& state) {
00323   absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
00324   for (auto _ : state) {
00325     benchmark::DoNotOptimize(v);
00326     benchmark::DoNotOptimize(v.size());
00327   }
00328 }
00329 BENCHMARK(BM_InlinedVectorSizeInlined);
00330 
00331 void BM_InlinedVectorSizeExternal(benchmark::State& state) {
00332   absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
00333   for (auto _ : state) {
00334     benchmark::DoNotOptimize(v);
00335     benchmark::DoNotOptimize(v.size());
00336   }
00337 }
00338 BENCHMARK(BM_InlinedVectorSizeExternal);
00339 
00340 void BM_StdVectorSize(benchmark::State& state) {
00341   std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
00342   for (auto _ : state) {
00343     benchmark::DoNotOptimize(v);
00344     benchmark::DoNotOptimize(v.size());
00345   }
00346 }
00347 BENCHMARK(BM_StdVectorSize);
00348 
00349 void BM_InlinedVectorEmptyInlined(benchmark::State& state) {
00350   absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7};
00351   for (auto _ : state) {
00352     benchmark::DoNotOptimize(v);
00353     benchmark::DoNotOptimize(v.empty());
00354   }
00355 }
00356 BENCHMARK(BM_InlinedVectorEmptyInlined);
00357 
00358 void BM_InlinedVectorEmptyExternal(benchmark::State& state) {
00359   absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
00360   for (auto _ : state) {
00361     benchmark::DoNotOptimize(v);
00362     benchmark::DoNotOptimize(v.empty());
00363   }
00364 }
00365 BENCHMARK(BM_InlinedVectorEmptyExternal);
00366 
00367 void BM_StdVectorEmpty(benchmark::State& state) {
00368   std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
00369   for (auto _ : state) {
00370     benchmark::DoNotOptimize(v);
00371     benchmark::DoNotOptimize(v.empty());
00372   }
00373 }
00374 BENCHMARK(BM_StdVectorEmpty);
00375 
00376 constexpr size_t kInlineElements = 4;
00377 constexpr size_t kSmallSize = kInlineElements / 2;
00378 constexpr size_t kLargeSize = kInlineElements * 2;
00379 constexpr size_t kBatchSize = 100;
00380 
00381 struct TrivialType {
00382   size_t val;
00383 };
00384 
00385 using TrivialVec = absl::InlinedVector<TrivialType, kInlineElements>;
00386 
00387 class NontrivialType {
00388  public:
00389   ABSL_ATTRIBUTE_NOINLINE NontrivialType() : val_() {}
00390 
00391   ABSL_ATTRIBUTE_NOINLINE NontrivialType(const NontrivialType& other)
00392       : val_(other.val_) {}
00393 
00394   ABSL_ATTRIBUTE_NOINLINE NontrivialType& operator=(
00395       const NontrivialType& other) {
00396     val_ = other.val_;
00397     return *this;
00398   }
00399 
00400   ABSL_ATTRIBUTE_NOINLINE ~NontrivialType() noexcept {}
00401 
00402  private:
00403   size_t val_;
00404 };
00405 
00406 using NontrivialVec = absl::InlinedVector<NontrivialType, kInlineElements>;
00407 
00408 template <typename VecT, typename PrepareVec, typename TestVec>
00409 void BatchedBenchmark(benchmark::State& state, PrepareVec prepare_vec,
00410                       TestVec test_vec) {
00411   VecT vectors[kBatchSize];
00412 
00413   while (state.KeepRunningBatch(kBatchSize)) {
00414     // Prepare batch
00415     state.PauseTiming();
00416     for (auto& vec : vectors) {
00417       prepare_vec(&vec);
00418     }
00419     benchmark::DoNotOptimize(vectors);
00420     state.ResumeTiming();
00421 
00422     // Test batch
00423     for (auto& vec : vectors) {
00424       test_vec(&vec);
00425     }
00426   }
00427 }
00428 
00429 template <typename VecT, size_t FromSize>
00430 void BM_Clear(benchmark::State& state) {
00431   BatchedBenchmark<VecT>(
00432       state,
00433       /* prepare_vec = */ [](VecT* vec) { vec->resize(FromSize); },
00434       /* test_vec = */ [](VecT* vec) { vec->clear(); });
00435 }
00436 
00437 BENCHMARK_TEMPLATE(BM_Clear, TrivialVec, kSmallSize);
00438 BENCHMARK_TEMPLATE(BM_Clear, TrivialVec, kLargeSize);
00439 
00440 BENCHMARK_TEMPLATE(BM_Clear, NontrivialVec, kSmallSize);
00441 BENCHMARK_TEMPLATE(BM_Clear, NontrivialVec, kLargeSize);
00442 
00443 }  // namespace


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:14