str_cat_benchmark.cc 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // Copyright 2018 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. #include "absl/strings/str_cat.h"
  15. #include <cstdint>
  16. #include <string>
  17. #include "benchmark/benchmark.h"
  18. #include "absl/strings/substitute.h"
  19. namespace {
  20. const char kStringOne[] = "Once Upon A Time, ";
  21. const char kStringTwo[] = "There was a string benchmark";
  22. // We want to include negative numbers in the benchmark, so this function
  23. // is used to count 0, 1, -1, 2, -2, 3, -3, ...
  24. inline int IncrementAlternatingSign(int i) {
  25. return i > 0 ? -i : 1 - i;
  26. }
  27. void BM_Sum_By_StrCat(benchmark::State& state) {
  28. int i = 0;
  29. char foo[100];
  30. for (auto _ : state) {
  31. // NOLINTNEXTLINE(runtime/printf)
  32. strcpy(foo, absl::StrCat(kStringOne, i, kStringTwo, i * 65536ULL).c_str());
  33. int sum = 0;
  34. for (char* f = &foo[0]; *f != 0; ++f) {
  35. sum += *f;
  36. }
  37. benchmark::DoNotOptimize(sum);
  38. i = IncrementAlternatingSign(i);
  39. }
  40. }
  41. BENCHMARK(BM_Sum_By_StrCat);
  42. void BM_StrCat_By_snprintf(benchmark::State& state) {
  43. int i = 0;
  44. char on_stack[1000];
  45. for (auto _ : state) {
  46. snprintf(on_stack, sizeof(on_stack), "%s %s:%d", kStringOne, kStringTwo, i);
  47. i = IncrementAlternatingSign(i);
  48. }
  49. }
  50. BENCHMARK(BM_StrCat_By_snprintf);
  51. void BM_StrCat_By_Strings(benchmark::State& state) {
  52. int i = 0;
  53. for (auto _ : state) {
  54. std::string result =
  55. std::string(kStringOne) + " " + kStringTwo + ":" + absl::StrCat(i);
  56. benchmark::DoNotOptimize(result);
  57. i = IncrementAlternatingSign(i);
  58. }
  59. }
  60. BENCHMARK(BM_StrCat_By_Strings);
  61. void BM_StrCat_By_StringOpPlus(benchmark::State& state) {
  62. int i = 0;
  63. for (auto _ : state) {
  64. std::string result = kStringOne;
  65. result += " ";
  66. result += kStringTwo;
  67. result += ":";
  68. result += absl::StrCat(i);
  69. benchmark::DoNotOptimize(result);
  70. i = IncrementAlternatingSign(i);
  71. }
  72. }
  73. BENCHMARK(BM_StrCat_By_StringOpPlus);
  74. void BM_StrCat_By_StrCat(benchmark::State& state) {
  75. int i = 0;
  76. for (auto _ : state) {
  77. std::string result = absl::StrCat(kStringOne, " ", kStringTwo, ":", i);
  78. benchmark::DoNotOptimize(result);
  79. i = IncrementAlternatingSign(i);
  80. }
  81. }
  82. BENCHMARK(BM_StrCat_By_StrCat);
  83. void BM_HexCat_By_StrCat(benchmark::State& state) {
  84. int i = 0;
  85. for (auto _ : state) {
  86. std::string result =
  87. absl::StrCat(kStringOne, " ", absl::Hex(int64_t{i} + 0x10000000));
  88. benchmark::DoNotOptimize(result);
  89. i = IncrementAlternatingSign(i);
  90. }
  91. }
  92. BENCHMARK(BM_HexCat_By_StrCat);
  93. void BM_HexCat_By_Substitute(benchmark::State& state) {
  94. int i = 0;
  95. for (auto _ : state) {
  96. std::string result = absl::Substitute(
  97. "$0 $1", kStringOne, reinterpret_cast<void*>(int64_t{i} + 0x10000000));
  98. benchmark::DoNotOptimize(result);
  99. i = IncrementAlternatingSign(i);
  100. }
  101. }
  102. BENCHMARK(BM_HexCat_By_Substitute);
  103. void BM_FloatToString_By_StrCat(benchmark::State& state) {
  104. int i = 0;
  105. float foo = 0.0f;
  106. for (auto _ : state) {
  107. std::string result = absl::StrCat(foo += 1.001f, " != ", int64_t{i});
  108. benchmark::DoNotOptimize(result);
  109. i = IncrementAlternatingSign(i);
  110. }
  111. }
  112. BENCHMARK(BM_FloatToString_By_StrCat);
  113. void BM_DoubleToString_By_SixDigits(benchmark::State& state) {
  114. int i = 0;
  115. double foo = 0.0;
  116. for (auto _ : state) {
  117. std::string result =
  118. absl::StrCat(absl::SixDigits(foo += 1.001), " != ", int64_t{i});
  119. benchmark::DoNotOptimize(result);
  120. i = IncrementAlternatingSign(i);
  121. }
  122. }
  123. BENCHMARK(BM_DoubleToString_By_SixDigits);
  124. template <typename... Chunks>
  125. void BM_StrAppendImpl(benchmark::State& state, size_t total_bytes,
  126. Chunks... chunks) {
  127. for (auto s : state) {
  128. std::string result;
  129. while (result.size() < total_bytes) {
  130. absl::StrAppend(&result, chunks...);
  131. benchmark::DoNotOptimize(result);
  132. }
  133. }
  134. }
  135. void BM_StrAppend(benchmark::State& state) {
  136. const int total_bytes = state.range(0);
  137. const int chunks_at_a_time = state.range(1);
  138. const absl::string_view kChunk = "0123456789";
  139. switch (chunks_at_a_time) {
  140. case 1:
  141. return BM_StrAppendImpl(state, total_bytes, kChunk);
  142. case 2:
  143. return BM_StrAppendImpl(state, total_bytes, kChunk, kChunk);
  144. case 4:
  145. return BM_StrAppendImpl(state, total_bytes, kChunk, kChunk, kChunk,
  146. kChunk);
  147. case 8:
  148. return BM_StrAppendImpl(state, total_bytes, kChunk, kChunk, kChunk,
  149. kChunk, kChunk, kChunk, kChunk, kChunk);
  150. default:
  151. std::abort();
  152. }
  153. }
  154. template <typename B>
  155. void StrAppendConfig(B* benchmark) {
  156. for (int bytes : {10, 100, 1000, 10000}) {
  157. for (int chunks : {1, 2, 4, 8}) {
  158. // Only add the ones that divide properly. Otherwise we are over counting.
  159. if (bytes % (10 * chunks) == 0) {
  160. benchmark->Args({bytes, chunks});
  161. }
  162. }
  163. }
  164. }
  165. BENCHMARK(BM_StrAppend)->Apply(StrAppendConfig);
  166. } // namespace