inlined_vector_benchmark.cc (25675B)
1 // Copyright 2019 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <array> 16 #include <string> 17 #include <vector> 18 19 #include "absl/base/internal/raw_logging.h" 20 #include "absl/base/macros.h" 21 #include "absl/container/inlined_vector.h" 22 #include "absl/strings/str_cat.h" 23 #include "benchmark/benchmark.h" 24 25 namespace { 26 27 void BM_InlinedVectorFill(benchmark::State& state) { 28 const int len = state.range(0); 29 absl::InlinedVector<int, 8> v; 30 v.reserve(len); 31 for (auto _ : state) { 32 v.resize(0); // Use resize(0) as InlinedVector releases storage on clear(). 33 for (int i = 0; i < len; ++i) { 34 v.push_back(i); 35 } 36 benchmark::DoNotOptimize(v); 37 } 38 } 39 BENCHMARK(BM_InlinedVectorFill)->Range(1, 256); 40 41 void BM_InlinedVectorFillRange(benchmark::State& state) { 42 const int len = state.range(0); 43 const std::vector<int> src(len, len); 44 absl::InlinedVector<int, 8> v; 45 v.reserve(len); 46 for (auto _ : state) { 47 benchmark::DoNotOptimize(src); 48 v.assign(src.begin(), src.end()); 49 benchmark::DoNotOptimize(v); 50 } 51 } 52 BENCHMARK(BM_InlinedVectorFillRange)->Range(1, 256); 53 54 void BM_StdVectorFill(benchmark::State& state) { 55 const int len = state.range(0); 56 std::vector<int> v; 57 v.reserve(len); 58 for (auto _ : state) { 59 v.clear(); 60 for (int i = 0; i < len; ++i) { 61 v.push_back(i); 62 } 63 benchmark::DoNotOptimize(v); 64 } 65 } 66 BENCHMARK(BM_StdVectorFill)->Range(1, 256); 67 68 // The purpose of the next two benchmarks is to verify that 69 // absl::InlinedVector is efficient when moving is more efficient than 70 // copying. To do so, we use strings that are larger than the short 71 // string optimization. 72 bool StringRepresentedInline(std::string s) { 73 const char* chars = s.data(); 74 std::string s1 = std::move(s); 75 return s1.data() != chars; 76 } 77 78 int GetNonShortStringOptimizationSize() { 79 for (int i = 24; i <= 192; i *= 2) { 80 if (!StringRepresentedInline(std::string(i, 'A'))) { 81 return i; 82 } 83 } 84 ABSL_RAW_LOG( 85 FATAL, 86 "Failed to find a string larger than the short string optimization"); 87 return -1; 88 } 89 90 void BM_InlinedVectorFillString(benchmark::State& state) { 91 const int len = state.range(0); 92 const int no_sso = GetNonShortStringOptimizationSize(); 93 std::string strings[4] = {std::string(no_sso, 'A'), std::string(no_sso, 'B'), 94 std::string(no_sso, 'C'), std::string(no_sso, 'D')}; 95 96 for (auto _ : state) { 97 absl::InlinedVector<std::string, 8> v; 98 for (int i = 0; i < len; i++) { 99 v.push_back(strings[i & 3]); 100 } 101 } 102 state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len); 103 } 104 BENCHMARK(BM_InlinedVectorFillString)->Range(0, 1024); 105 106 void BM_StdVectorFillString(benchmark::State& state) { 107 const int len = state.range(0); 108 const int no_sso = GetNonShortStringOptimizationSize(); 109 std::string strings[4] = {std::string(no_sso, 'A'), std::string(no_sso, 'B'), 110 std::string(no_sso, 'C'), std::string(no_sso, 'D')}; 111 112 for (auto _ : state) { 113 std::vector<std::string> v; 114 for (int i = 0; i < len; i++) { 115 v.push_back(strings[i & 3]); 116 } 117 } 118 state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len); 119 } 120 BENCHMARK(BM_StdVectorFillString)->Range(0, 1024); 121 122 struct Buffer { // some arbitrary structure for benchmarking. 123 char* base; 124 int length; 125 int capacity; 126 void* user_data; 127 }; 128 129 void BM_InlinedVectorAssignments(benchmark::State& state) { 130 const int len = state.range(0); 131 using BufferVec = absl::InlinedVector<Buffer, 2>; 132 133 BufferVec src; 134 src.resize(len); 135 136 BufferVec dst; 137 for (auto _ : state) { 138 benchmark::DoNotOptimize(dst); 139 benchmark::DoNotOptimize(src); 140 dst = src; 141 } 142 } 143 BENCHMARK(BM_InlinedVectorAssignments) 144 ->Arg(0) 145 ->Arg(1) 146 ->Arg(2) 147 ->Arg(3) 148 ->Arg(4) 149 ->Arg(20); 150 151 void BM_CreateFromContainer(benchmark::State& state) { 152 for (auto _ : state) { 153 absl::InlinedVector<int, 4> src{1, 2, 3}; 154 benchmark::DoNotOptimize(src); 155 absl::InlinedVector<int, 4> dst(std::move(src)); 156 benchmark::DoNotOptimize(dst); 157 } 158 } 159 BENCHMARK(BM_CreateFromContainer); 160 161 struct LargeCopyableOnly { 162 LargeCopyableOnly() : d(1024, 17) {} 163 LargeCopyableOnly(const LargeCopyableOnly& o) = default; 164 LargeCopyableOnly& operator=(const LargeCopyableOnly& o) = default; 165 166 std::vector<int> d; 167 }; 168 169 struct LargeCopyableSwappable { 170 LargeCopyableSwappable() : d(1024, 17) {} 171 172 LargeCopyableSwappable(const LargeCopyableSwappable& o) = default; 173 174 LargeCopyableSwappable& operator=(LargeCopyableSwappable o) { 175 using std::swap; 176 swap(*this, o); 177 return *this; 178 } 179 180 friend void swap(LargeCopyableSwappable& a, LargeCopyableSwappable& b) { 181 using std::swap; 182 swap(a.d, b.d); 183 } 184 185 std::vector<int> d; 186 }; 187 188 struct LargeCopyableMovable { 189 LargeCopyableMovable() : d(1024, 17) {} 190 // Use implicitly defined copy and move. 191 192 std::vector<int> d; 193 }; 194 195 struct LargeCopyableMovableSwappable { 196 LargeCopyableMovableSwappable() : d(1024, 17) {} 197 LargeCopyableMovableSwappable(const LargeCopyableMovableSwappable& o) = 198 default; 199 LargeCopyableMovableSwappable(LargeCopyableMovableSwappable&& o) = default; 200 201 LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable o) { 202 using std::swap; 203 swap(*this, o); 204 return *this; 205 } 206 LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable&& o) = 207 default; 208 209 friend void swap(LargeCopyableMovableSwappable& a, 210 LargeCopyableMovableSwappable& b) { 211 using std::swap; 212 swap(a.d, b.d); 213 } 214 215 std::vector<int> d; 216 }; 217 218 template <typename ElementType> 219 void BM_SwapElements(benchmark::State& state) { 220 const int len = state.range(0); 221 using Vec = absl::InlinedVector<ElementType, 32>; 222 Vec a(len); 223 Vec b; 224 for (auto _ : state) { 225 using std::swap; 226 benchmark::DoNotOptimize(a); 227 benchmark::DoNotOptimize(b); 228 swap(a, b); 229 } 230 } 231 BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableOnly)->Range(0, 1024); 232 BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableSwappable)->Range(0, 1024); 233 BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovable)->Range(0, 1024); 234 BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovableSwappable) 235 ->Range(0, 1024); 236 237 // The following benchmark is meant to track the efficiency of the vector size 238 // as a function of stored type via the benchmark label. It is not meant to 239 // output useful sizeof operator performance. The loop is a dummy operation 240 // to fulfill the requirement of running the benchmark. 241 template <typename VecType> 242 void BM_Sizeof(benchmark::State& state) { 243 int size = 0; 244 for (auto _ : state) { 245 VecType vec; 246 size = sizeof(vec); 247 } 248 state.SetLabel(absl::StrCat("sz=", size)); 249 } 250 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 1>); 251 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 4>); 252 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 7>); 253 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 8>); 254 255 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 1>); 256 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 4>); 257 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 7>); 258 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 8>); 259 260 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 1>); 261 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 4>); 262 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 7>); 263 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 8>); 264 265 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 1>); 266 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 4>); 267 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 7>); 268 BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 8>); 269 270 void BM_InlinedVectorIndexInlined(benchmark::State& state) { 271 absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7}; 272 for (auto _ : state) { 273 benchmark::DoNotOptimize(v); 274 benchmark::DoNotOptimize(v[4]); 275 } 276 } 277 BENCHMARK(BM_InlinedVectorIndexInlined); 278 279 void BM_InlinedVectorIndexExternal(benchmark::State& state) { 280 absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 281 for (auto _ : state) { 282 benchmark::DoNotOptimize(v); 283 benchmark::DoNotOptimize(v[4]); 284 } 285 } 286 BENCHMARK(BM_InlinedVectorIndexExternal); 287 288 void BM_StdVectorIndex(benchmark::State& state) { 289 std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 290 for (auto _ : state) { 291 benchmark::DoNotOptimize(v); 292 benchmark::DoNotOptimize(v[4]); 293 } 294 } 295 BENCHMARK(BM_StdVectorIndex); 296 297 void BM_InlinedVectorDataInlined(benchmark::State& state) { 298 absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7}; 299 for (auto _ : state) { 300 benchmark::DoNotOptimize(v); 301 benchmark::DoNotOptimize(v.data()); 302 } 303 } 304 BENCHMARK(BM_InlinedVectorDataInlined); 305 306 void BM_InlinedVectorDataExternal(benchmark::State& state) { 307 absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 308 for (auto _ : state) { 309 benchmark::DoNotOptimize(v); 310 benchmark::DoNotOptimize(v.data()); 311 } 312 state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); 313 } 314 BENCHMARK(BM_InlinedVectorDataExternal); 315 316 void BM_StdVectorData(benchmark::State& state) { 317 std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 318 for (auto _ : state) { 319 benchmark::DoNotOptimize(v); 320 benchmark::DoNotOptimize(v.data()); 321 } 322 state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); 323 } 324 BENCHMARK(BM_StdVectorData); 325 326 void BM_InlinedVectorSizeInlined(benchmark::State& state) { 327 absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7}; 328 for (auto _ : state) { 329 benchmark::DoNotOptimize(v); 330 benchmark::DoNotOptimize(v.size()); 331 } 332 } 333 BENCHMARK(BM_InlinedVectorSizeInlined); 334 335 void BM_InlinedVectorSizeExternal(benchmark::State& state) { 336 absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 337 for (auto _ : state) { 338 benchmark::DoNotOptimize(v); 339 benchmark::DoNotOptimize(v.size()); 340 } 341 } 342 BENCHMARK(BM_InlinedVectorSizeExternal); 343 344 void BM_StdVectorSize(benchmark::State& state) { 345 std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 346 for (auto _ : state) { 347 benchmark::DoNotOptimize(v); 348 benchmark::DoNotOptimize(v.size()); 349 } 350 } 351 BENCHMARK(BM_StdVectorSize); 352 353 void BM_InlinedVectorEmptyInlined(benchmark::State& state) { 354 absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7}; 355 for (auto _ : state) { 356 benchmark::DoNotOptimize(v); 357 benchmark::DoNotOptimize(v.empty()); 358 } 359 } 360 BENCHMARK(BM_InlinedVectorEmptyInlined); 361 362 void BM_InlinedVectorEmptyExternal(benchmark::State& state) { 363 absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 364 for (auto _ : state) { 365 benchmark::DoNotOptimize(v); 366 benchmark::DoNotOptimize(v.empty()); 367 } 368 } 369 BENCHMARK(BM_InlinedVectorEmptyExternal); 370 371 void BM_StdVectorEmpty(benchmark::State& state) { 372 std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 373 for (auto _ : state) { 374 benchmark::DoNotOptimize(v); 375 benchmark::DoNotOptimize(v.empty()); 376 } 377 } 378 BENCHMARK(BM_StdVectorEmpty); 379 380 constexpr size_t kInlinedCapacity = 4; 381 constexpr size_t kLargeSize = kInlinedCapacity * 2; 382 constexpr size_t kSmallSize = kInlinedCapacity / 2; 383 constexpr size_t kBatchSize = 100; 384 385 #define ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_FunctionTemplate, T) \ 386 BENCHMARK_TEMPLATE(BM_FunctionTemplate, T, kLargeSize); \ 387 BENCHMARK_TEMPLATE(BM_FunctionTemplate, T, kSmallSize) 388 389 #define ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_FunctionTemplate, T) \ 390 BENCHMARK_TEMPLATE(BM_FunctionTemplate, T, kLargeSize, kLargeSize); \ 391 BENCHMARK_TEMPLATE(BM_FunctionTemplate, T, kLargeSize, kSmallSize); \ 392 BENCHMARK_TEMPLATE(BM_FunctionTemplate, T, kSmallSize, kLargeSize); \ 393 BENCHMARK_TEMPLATE(BM_FunctionTemplate, T, kSmallSize, kSmallSize) 394 395 template <typename T> 396 using InlVec = absl::InlinedVector<T, kInlinedCapacity>; 397 398 struct TrivialType { 399 size_t val; 400 }; 401 402 class NontrivialType { 403 public: 404 ABSL_ATTRIBUTE_NOINLINE NontrivialType() : val_() { 405 benchmark::DoNotOptimize(*this); 406 } 407 408 ABSL_ATTRIBUTE_NOINLINE NontrivialType(const NontrivialType& other) 409 : val_(other.val_) { 410 benchmark::DoNotOptimize(*this); 411 } 412 413 ABSL_ATTRIBUTE_NOINLINE NontrivialType& operator=( 414 const NontrivialType& other) { 415 val_ = other.val_; 416 benchmark::DoNotOptimize(*this); 417 return *this; 418 } 419 420 ABSL_ATTRIBUTE_NOINLINE ~NontrivialType() noexcept { 421 benchmark::DoNotOptimize(*this); 422 } 423 424 private: 425 size_t val_; 426 }; 427 428 template <typename T, typename PrepareVecFn, typename TestVecFn> 429 void BatchedBenchmark(benchmark::State& state, PrepareVecFn prepare_vec, 430 TestVecFn test_vec) { 431 std::array<InlVec<T>, kBatchSize> vector_batch{}; 432 433 while (state.KeepRunningBatch(kBatchSize)) { 434 // Prepare batch 435 state.PauseTiming(); 436 for (size_t i = 0; i < kBatchSize; ++i) { 437 prepare_vec(vector_batch.data() + i, i); 438 } 439 benchmark::DoNotOptimize(vector_batch); 440 state.ResumeTiming(); 441 442 // Test batch 443 for (size_t i = 0; i < kBatchSize; ++i) { 444 test_vec(vector_batch.data() + i, i); 445 } 446 } 447 } 448 449 template <typename T, size_t ToSize> 450 void BM_ConstructFromSize(benchmark::State& state) { 451 using VecT = InlVec<T>; 452 auto size = ToSize; 453 BatchedBenchmark<T>( 454 state, 455 /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->~VecT(); }, 456 /* test_vec = */ 457 [&](void* ptr, size_t) { 458 benchmark::DoNotOptimize(size); 459 ::new (ptr) VecT(size); 460 }); 461 } 462 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromSize, TrivialType); 463 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromSize, NontrivialType); 464 465 template <typename T, size_t ToSize> 466 void BM_ConstructFromSizeRef(benchmark::State& state) { 467 using VecT = InlVec<T>; 468 auto size = ToSize; 469 auto ref = T(); 470 BatchedBenchmark<T>( 471 state, 472 /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->~VecT(); }, 473 /* test_vec = */ 474 [&](void* ptr, size_t) { 475 benchmark::DoNotOptimize(size); 476 benchmark::DoNotOptimize(ref); 477 ::new (ptr) VecT(size, ref); 478 }); 479 } 480 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromSizeRef, TrivialType); 481 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromSizeRef, NontrivialType); 482 483 template <typename T, size_t ToSize> 484 void BM_ConstructFromRange(benchmark::State& state) { 485 using VecT = InlVec<T>; 486 std::array<T, ToSize> arr{}; 487 BatchedBenchmark<T>( 488 state, 489 /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->~VecT(); }, 490 /* test_vec = */ 491 [&](void* ptr, size_t) { 492 benchmark::DoNotOptimize(arr); 493 ::new (ptr) VecT(arr.begin(), arr.end()); 494 }); 495 } 496 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromRange, TrivialType); 497 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromRange, NontrivialType); 498 499 template <typename T, size_t ToSize> 500 void BM_ConstructFromCopy(benchmark::State& state) { 501 using VecT = InlVec<T>; 502 VecT other_vec(ToSize); 503 BatchedBenchmark<T>( 504 state, 505 /* prepare_vec = */ 506 [](InlVec<T>* vec, size_t) { vec->~VecT(); }, 507 /* test_vec = */ 508 [&](void* ptr, size_t) { 509 benchmark::DoNotOptimize(other_vec); 510 ::new (ptr) VecT(other_vec); 511 }); 512 } 513 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromCopy, TrivialType); 514 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromCopy, NontrivialType); 515 516 template <typename T, size_t ToSize> 517 void BM_ConstructFromMove(benchmark::State& state) { 518 using VecT = InlVec<T>; 519 std::array<VecT, kBatchSize> vector_batch{}; 520 BatchedBenchmark<T>( 521 state, 522 /* prepare_vec = */ 523 [&](InlVec<T>* vec, size_t i) { 524 vector_batch[i].clear(); 525 vector_batch[i].resize(ToSize); 526 vec->~VecT(); 527 }, 528 /* test_vec = */ 529 [&](void* ptr, size_t i) { 530 benchmark::DoNotOptimize(vector_batch[i]); 531 ::new (ptr) VecT(std::move(vector_batch[i])); 532 }); 533 } 534 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromMove, TrivialType); 535 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_ConstructFromMove, NontrivialType); 536 537 // Measure cost of copy-constructor+destructor. 538 void BM_CopyTrivial(benchmark::State& state) { 539 const int n = state.range(0); 540 InlVec<int64_t> src(n); 541 for (auto s : state) { 542 InlVec<int64_t> copy(src); 543 benchmark::DoNotOptimize(copy); 544 } 545 } 546 BENCHMARK(BM_CopyTrivial)->Arg(0)->Arg(1)->Arg(kLargeSize); 547 548 // Measure cost of copy-constructor+destructor. 549 void BM_CopyNonTrivial(benchmark::State& state) { 550 const int n = state.range(0); 551 InlVec<InlVec<int64_t>> src(n); 552 for (auto s : state) { 553 InlVec<InlVec<int64_t>> copy(src); 554 benchmark::DoNotOptimize(copy); 555 } 556 } 557 BENCHMARK(BM_CopyNonTrivial)->Arg(0)->Arg(1)->Arg(kLargeSize); 558 559 template <typename T, size_t FromSize, size_t ToSize> 560 void BM_AssignSizeRef(benchmark::State& state) { 561 auto size = ToSize; 562 auto ref = T(); 563 BatchedBenchmark<T>( 564 state, 565 /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->resize(FromSize); }, 566 /* test_vec = */ 567 [&](InlVec<T>* vec, size_t) { 568 benchmark::DoNotOptimize(size); 569 benchmark::DoNotOptimize(ref); 570 vec->assign(size, ref); 571 }); 572 } 573 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_AssignSizeRef, TrivialType); 574 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_AssignSizeRef, NontrivialType); 575 576 template <typename T, size_t FromSize, size_t ToSize> 577 void BM_AssignRange(benchmark::State& state) { 578 std::array<T, ToSize> arr{}; 579 BatchedBenchmark<T>( 580 state, 581 /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->resize(FromSize); }, 582 /* test_vec = */ 583 [&](InlVec<T>* vec, size_t) { 584 benchmark::DoNotOptimize(arr); 585 vec->assign(arr.begin(), arr.end()); 586 }); 587 } 588 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_AssignRange, TrivialType); 589 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_AssignRange, NontrivialType); 590 591 template <typename T, size_t FromSize, size_t ToSize> 592 void BM_AssignFromCopy(benchmark::State& state) { 593 InlVec<T> other_vec(ToSize); 594 BatchedBenchmark<T>( 595 state, 596 /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->resize(FromSize); }, 597 /* test_vec = */ 598 [&](InlVec<T>* vec, size_t) { 599 benchmark::DoNotOptimize(other_vec); 600 *vec = other_vec; 601 }); 602 } 603 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_AssignFromCopy, TrivialType); 604 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_AssignFromCopy, NontrivialType); 605 606 template <typename T, size_t FromSize, size_t ToSize> 607 void BM_AssignFromMove(benchmark::State& state) { 608 using VecT = InlVec<T>; 609 std::array<VecT, kBatchSize> vector_batch{}; 610 BatchedBenchmark<T>( 611 state, 612 /* prepare_vec = */ 613 [&](InlVec<T>* vec, size_t i) { 614 vector_batch[i].clear(); 615 vector_batch[i].resize(ToSize); 616 vec->resize(FromSize); 617 }, 618 /* test_vec = */ 619 [&](InlVec<T>* vec, size_t i) { 620 benchmark::DoNotOptimize(vector_batch[i]); 621 *vec = std::move(vector_batch[i]); 622 }); 623 } 624 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_AssignFromMove, TrivialType); 625 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_AssignFromMove, NontrivialType); 626 627 template <typename T, size_t FromSize, size_t ToSize> 628 void BM_ResizeSize(benchmark::State& state) { 629 BatchedBenchmark<T>( 630 state, 631 /* prepare_vec = */ 632 [](InlVec<T>* vec, size_t) { 633 vec->clear(); 634 vec->resize(FromSize); 635 }, 636 /* test_vec = */ 637 [](InlVec<T>* vec, size_t) { vec->resize(ToSize); }); 638 } 639 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_ResizeSize, TrivialType); 640 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_ResizeSize, NontrivialType); 641 642 template <typename T, size_t FromSize, size_t ToSize> 643 void BM_ResizeSizeRef(benchmark::State& state) { 644 auto t = T(); 645 BatchedBenchmark<T>( 646 state, 647 /* prepare_vec = */ 648 [](InlVec<T>* vec, size_t) { 649 vec->clear(); 650 vec->resize(FromSize); 651 }, 652 /* test_vec = */ 653 [&](InlVec<T>* vec, size_t) { 654 benchmark::DoNotOptimize(t); 655 vec->resize(ToSize, t); 656 }); 657 } 658 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_ResizeSizeRef, TrivialType); 659 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_ResizeSizeRef, NontrivialType); 660 661 template <typename T, size_t FromSize, size_t ToSize> 662 void BM_InsertSizeRef(benchmark::State& state) { 663 auto t = T(); 664 BatchedBenchmark<T>( 665 state, 666 /* prepare_vec = */ 667 [](InlVec<T>* vec, size_t) { 668 vec->clear(); 669 vec->resize(FromSize); 670 }, 671 /* test_vec = */ 672 [&](InlVec<T>* vec, size_t) { 673 benchmark::DoNotOptimize(t); 674 auto* pos = vec->data() + (vec->size() / 2); 675 vec->insert(pos, t); 676 }); 677 } 678 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_InsertSizeRef, TrivialType); 679 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_InsertSizeRef, NontrivialType); 680 681 template <typename T, size_t FromSize, size_t ToSize> 682 void BM_InsertRange(benchmark::State& state) { 683 InlVec<T> other_vec(ToSize); 684 BatchedBenchmark<T>( 685 state, 686 /* prepare_vec = */ 687 [](InlVec<T>* vec, size_t) { 688 vec->clear(); 689 vec->resize(FromSize); 690 }, 691 /* test_vec = */ 692 [&](InlVec<T>* vec, size_t) { 693 benchmark::DoNotOptimize(other_vec); 694 auto* pos = vec->data() + (vec->size() / 2); 695 vec->insert(pos, other_vec.begin(), other_vec.end()); 696 }); 697 } 698 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_InsertRange, TrivialType); 699 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_InsertRange, NontrivialType); 700 701 template <typename T, size_t FromSize> 702 void BM_EmplaceBack(benchmark::State& state) { 703 BatchedBenchmark<T>( 704 state, 705 /* prepare_vec = */ 706 [](InlVec<T>* vec, size_t) { 707 vec->clear(); 708 vec->resize(FromSize); 709 }, 710 /* test_vec = */ 711 [](InlVec<T>* vec, size_t) { vec->emplace_back(); }); 712 } 713 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_EmplaceBack, TrivialType); 714 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_EmplaceBack, NontrivialType); 715 716 template <typename T, size_t FromSize> 717 void BM_PopBack(benchmark::State& state) { 718 BatchedBenchmark<T>( 719 state, 720 /* prepare_vec = */ 721 [](InlVec<T>* vec, size_t) { 722 vec->clear(); 723 vec->resize(FromSize); 724 }, 725 /* test_vec = */ 726 [](InlVec<T>* vec, size_t) { vec->pop_back(); }); 727 } 728 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_PopBack, TrivialType); 729 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_PopBack, NontrivialType); 730 731 template <typename T, size_t FromSize> 732 void BM_EraseOne(benchmark::State& state) { 733 BatchedBenchmark<T>( 734 state, 735 /* prepare_vec = */ 736 [](InlVec<T>* vec, size_t) { 737 vec->clear(); 738 vec->resize(FromSize); 739 }, 740 /* test_vec = */ 741 [](InlVec<T>* vec, size_t) { 742 auto* pos = vec->data() + (vec->size() / 2); 743 vec->erase(pos); 744 }); 745 } 746 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_EraseOne, TrivialType); 747 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_EraseOne, NontrivialType); 748 749 template <typename T, size_t FromSize> 750 void BM_EraseRange(benchmark::State& state) { 751 BatchedBenchmark<T>( 752 state, 753 /* prepare_vec = */ 754 [](InlVec<T>* vec, size_t) { 755 vec->clear(); 756 vec->resize(FromSize); 757 }, 758 /* test_vec = */ 759 [](InlVec<T>* vec, size_t) { 760 auto* pos = vec->data() + (vec->size() / 2); 761 vec->erase(pos, pos + 1); 762 }); 763 } 764 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_EraseRange, TrivialType); 765 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_EraseRange, NontrivialType); 766 767 template <typename T, size_t FromSize> 768 void BM_Clear(benchmark::State& state) { 769 BatchedBenchmark<T>( 770 state, 771 /* prepare_vec = */ [](InlVec<T>* vec, size_t) { vec->resize(FromSize); }, 772 /* test_vec = */ [](InlVec<T>* vec, size_t) { vec->clear(); }); 773 } 774 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_Clear, TrivialType); 775 ABSL_INTERNAL_BENCHMARK_ONE_SIZE(BM_Clear, NontrivialType); 776 777 template <typename T, size_t FromSize, size_t ToCapacity> 778 void BM_Reserve(benchmark::State& state) { 779 BatchedBenchmark<T>( 780 state, 781 /* prepare_vec = */ 782 [](InlVec<T>* vec, size_t) { 783 vec->clear(); 784 vec->resize(FromSize); 785 }, 786 /* test_vec = */ 787 [](InlVec<T>* vec, size_t) { vec->reserve(ToCapacity); }); 788 } 789 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_Reserve, TrivialType); 790 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_Reserve, NontrivialType); 791 792 template <typename T, size_t FromCapacity, size_t ToCapacity> 793 void BM_ShrinkToFit(benchmark::State& state) { 794 BatchedBenchmark<T>( 795 state, 796 /* prepare_vec = */ 797 [](InlVec<T>* vec, size_t) { 798 vec->clear(); 799 vec->resize(ToCapacity); 800 vec->reserve(FromCapacity); 801 }, 802 /* test_vec = */ [](InlVec<T>* vec, size_t) { vec->shrink_to_fit(); }); 803 } 804 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_ShrinkToFit, TrivialType); 805 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_ShrinkToFit, NontrivialType); 806 807 template <typename T, size_t FromSize, size_t ToSize> 808 void BM_Swap(benchmark::State& state) { 809 using VecT = InlVec<T>; 810 std::array<VecT, kBatchSize> vector_batch{}; 811 BatchedBenchmark<T>( 812 state, 813 /* prepare_vec = */ 814 [&](InlVec<T>* vec, size_t i) { 815 vector_batch[i].clear(); 816 vector_batch[i].resize(ToSize); 817 vec->resize(FromSize); 818 }, 819 /* test_vec = */ 820 [&](InlVec<T>* vec, size_t i) { 821 using std::swap; 822 benchmark::DoNotOptimize(vector_batch[i]); 823 swap(*vec, vector_batch[i]); 824 }); 825 } 826 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_Swap, TrivialType); 827 ABSL_INTERNAL_BENCHMARK_TWO_SIZE(BM_Swap, NontrivialType); 828 829 } // namespace