00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
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
00065
00066
00067
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 {
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
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
00234
00235
00236
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
00415 state.PauseTiming();
00416 for (auto& vec : vectors) {
00417 prepare_vec(&vec);
00418 }
00419 benchmark::DoNotOptimize(vectors);
00420 state.ResumeTiming();
00421
00422
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 [](VecT* vec) { vec->resize(FromSize); },
00434 [](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 }