proxygen
FormatBenchmark.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2012-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <folly/Format.h>
18 
19 #include <glog/logging.h>
20 
21 #include <folly/Benchmark.h>
22 #include <folly/FBVector.h>
23 #include <folly/Utility.h>
24 #include <folly/dynamic.h>
25 #include <folly/init/Init.h>
26 #include <folly/json.h>
27 
28 using namespace folly;
29 
30 namespace {
31 
32 std::array<char, 300> bigBuf;
33 
34 std::string getShortString() {
35  return "ABCDEFGHIJ";
36 }
37 
38 std::string getLongString() {
39  return std::string(256, 'A');
40 }
41 
42 } // namespace
43 
44 BENCHMARK(octal_snprintf, iters) {
45  while (iters--) {
46  snprintf(
47  bigBuf.data(), bigBuf.size(), "%o", static_cast<unsigned int>(iters));
48  }
49 }
50 
51 BENCHMARK_RELATIVE(octal_uintToOctal, iters) {
52  while (iters--) {
54  bigBuf.data(),
56  static_cast<unsigned int>(iters));
57  }
58 }
59 
61 
62 BENCHMARK(hex_snprintf, iters) {
63  while (iters--) {
64  snprintf(
65  bigBuf.data(), bigBuf.size(), "%x", static_cast<unsigned int>(iters));
66  }
67 }
68 
69 BENCHMARK_RELATIVE(hex_uintToHex, iters) {
70  while (iters--) {
72  bigBuf.data(), detail::kMaxHexLength, static_cast<unsigned int>(iters));
73  }
74 }
75 
77 
78 BENCHMARK(intAppend_snprintf) {
79  fbstring out;
80  for (int i = -1000; i < 1000; i++) {
81  snprintf(bigBuf.data(), bigBuf.size(), "%d", i);
82  out.append(bigBuf.data());
83  }
84 }
85 
86 BENCHMARK_RELATIVE(intAppend_to) {
87  fbstring out;
88  for (int i = -1000; i < 1000; i++) {
89  toAppend(i, &out);
90  }
91 }
92 
93 BENCHMARK_RELATIVE(intAppend_format) {
94  fbstring out;
95  for (int i = -1000; i < 1000; i++) {
96  format(&out, "{}", i);
97  }
98 }
99 
101 
102 template <size_t... Indexes>
104  static_assert(20 == sizeof...(Indexes), "Must have exactly 20 indexes");
105  return snprintf(
106  bigBuf.data(),
107  bigBuf.size(),
108  "%d %d %d %d %d"
109  "%d %d %d %d %d"
110  "%d %d %d %d %d"
111  "%d %d %d %d %d",
112  (i + static_cast<int>(Indexes))...);
113 }
114 
115 BENCHMARK(bigFormat_snprintf, iters) {
116  while (iters--) {
117  for (int i = -100; i < 100; i++) {
119  }
120  }
121 }
122 
123 template <size_t... Indexes>
124 decltype(auto) format20Numbers(int i, index_sequence<Indexes...>) {
125  static_assert(20 == sizeof...(Indexes), "Must have exactly 20 indexes");
126  return format(
127  "{} {} {} {} {}"
128  "{} {} {} {} {}"
129  "{} {} {} {} {}"
130  "{} {} {} {} {}",
131  (i + static_cast<int>(Indexes))...);
132 }
133 
134 BENCHMARK_RELATIVE(bigFormat_format, iters) {
135  BenchmarkSuspender suspender;
136  char* p;
137  auto writeToBuf = [&p](StringPiece sp) mutable {
138  memcpy(p, sp.data(), sp.size());
139  p += sp.size();
140  };
141 
142  while (iters--) {
143  for (int i = -100; i < 100; i++) {
144  p = bigBuf.data();
145  suspender.dismissing(
146  [&] { format20Numbers(i, make_index_sequence<20>())(writeToBuf); });
147  }
148  }
149 }
150 
152 
153 BENCHMARK(format_nested_strings, iters) {
154  BenchmarkSuspender suspender;
155  while (iters--) {
156  for (int i = 0; i < 1000; ++i) {
157  fbstring out;
158  suspender.dismissing([&] {
159  format(
160  &out,
161  "{} {}",
162  format("{} {}", i, i + 1).str(),
163  format("{} {}", -i, -i - 1).str());
164  });
165  }
166  }
167 }
168 
169 BENCHMARK_RELATIVE(format_nested_fbstrings, iters) {
170  BenchmarkSuspender suspender;
171  while (iters--) {
172  for (int i = 0; i < 1000; ++i) {
173  fbstring out;
174  suspender.dismissing([&] {
175  format(
176  &out,
177  "{} {}",
178  format("{} {}", i, i + 1).fbstr(),
179  format("{} {}", -i, -i - 1).fbstr());
180  });
181  }
182  }
183 }
184 
185 BENCHMARK_RELATIVE(format_nested_direct, iters) {
186  BenchmarkSuspender suspender;
187  while (iters--) {
188  for (int i = 0; i < 1000; ++i) {
189  fbstring out;
190  suspender.dismissing([&] {
191  format(
192  &out,
193  "{} {}",
194  format("{} {}", i, i + 1),
195  format("{} {}", -i, -i - 1));
196  });
197  }
198  }
199 }
200 
202 
203 BENCHMARK(copy_short_string, iters) {
204  BenchmarkSuspender suspender;
205  auto const& shortString = getShortString();
206  while (iters--) {
207  fbstring out;
208  suspender.dismissing([&] { out = shortString; });
209  }
210 }
211 
212 BENCHMARK_RELATIVE(format_short_string_unsafe, iters) {
213  BenchmarkSuspender suspender;
214  auto const& shortString = getShortString();
215  while (iters--) {
216  fbstring out;
217  suspender.dismissing([&] { format(&out, shortString); });
218  }
219 }
220 
221 BENCHMARK_RELATIVE(format_short_string_safe, iters) {
222  BenchmarkSuspender suspender;
223  auto const& shortString = getShortString();
224  while (iters--) {
225  fbstring out;
226  suspender.dismissing([&] { format(&out, "{}", shortString); });
227  }
228 }
229 
230 BENCHMARK_RELATIVE(sformat_short_string_unsafe, iters) {
231  BenchmarkSuspender suspender;
232  auto const& shortString = getShortString();
233  while (iters--) {
234  std::string out;
235  suspender.dismissing([&] { out = sformat(shortString); });
236  }
237 }
238 
239 BENCHMARK_RELATIVE(sformat_short_string_safe, iters) {
240  BenchmarkSuspender suspender;
241  auto const& shortString = getShortString();
242  while (iters--) {
243  std::string out;
244  suspender.dismissing([&] { out = sformat("{}", shortString); });
245  }
246 }
247 
249 
250 BENCHMARK(copy_long_string, iters) {
251  BenchmarkSuspender suspender;
252  auto const& longString = getLongString();
253  while (iters--) {
254  fbstring out;
255  suspender.dismissing([&] { out = longString; });
256  }
257 }
258 
259 BENCHMARK_RELATIVE(format_long_string_unsafe, iters) {
260  BenchmarkSuspender suspender;
261  auto const& longString = getLongString();
262  while (iters--) {
263  fbstring out;
264  suspender.dismissing([&] { format(&out, longString); });
265  }
266 }
267 
268 BENCHMARK_RELATIVE(format_long_string_safe, iters) {
269  BenchmarkSuspender suspender;
270  auto const& longString = getLongString();
271  while (iters--) {
272  fbstring out;
273  suspender.dismissing([&] { format(&out, "{}", longString); });
274  }
275 }
276 
277 BENCHMARK_RELATIVE(sformat_long_string_unsafe, iters) {
278  BenchmarkSuspender suspender;
279  auto const& longString = getLongString();
280  while (iters--) {
281  std::string out;
282  suspender.dismissing([&] { out = sformat(longString); });
283  }
284 }
285 
286 BENCHMARK_RELATIVE(sformat_long_string_safe, iters) {
287  BenchmarkSuspender suspender;
288  auto const& longString = getLongString();
289  while (iters--) {
290  std::string out;
291  suspender.dismissing([&] { out = sformat("{}", longString); });
292  }
293 }
294 
295 // Benchmark results on my dev server (20-core Intel Xeon E5-2660 v2 @ 2.20GHz)
296 //
297 // ============================================================================
298 // folly/test/FormatBenchmark.cpp relative time/iter iters/s
299 // ============================================================================
300 // octal_snprintf 79.30ns 12.61M
301 // octal_uintToOctal 3452.19% 2.30ns 435.35M
302 // ----------------------------------------------------------------------------
303 // hex_snprintf 73.59ns 13.59M
304 // hex_uintToHex 4507.53% 1.63ns 612.49M
305 // ----------------------------------------------------------------------------
306 // intAppend_snprintf 191.50us 5.22K
307 // intAppend_to 552.46% 34.66us 28.85K
308 // intAppend_format 215.76% 88.76us 11.27K
309 // ----------------------------------------------------------------------------
310 // bigFormat_snprintf 178.03us 5.62K
311 // bigFormat_format 90.41% 196.91us 5.08K
312 // ----------------------------------------------------------------------------
313 // format_nested_strings 317.65us 3.15K
314 // format_nested_fbstrings 99.89% 318.01us 3.14K
315 // format_nested_direct 116.52% 272.62us 3.67K
316 // ----------------------------------------------------------------------------
317 // copy_short_string 28.33ns 35.30M
318 // format_short_string_unsafe 82.51% 34.33ns 29.13M
319 // format_short_string_safe 58.92% 48.08ns 20.80M
320 // sformat_short_string_unsafe 73.90% 38.33ns 26.09M
321 // sformat_short_string_safe 54.97% 51.53ns 19.41M
322 // ----------------------------------------------------------------------------
323 // copy_long_string 57.56ns 17.37M
324 // format_long_string_unsafe 68.79% 83.68ns 11.95M
325 // format_long_string_safe 69.44% 82.89ns 12.06M
326 // sformat_long_string_unsafe 65.58% 87.77ns 11.39M
327 // sformat_long_string_safe 68.14% 84.47ns 11.84M
328 // ============================================================================
329 
330 int main(int argc, char* argv[]) {
331  init(&argc, &argv, true);
332  runBenchmarks();
333  return 0;
334 }
std::string sformat(StringPiece fmt, Args &&...args)
Definition: Format.h:280
int snprintf20Numbers(int i, index_sequence< Indexes... >)
decltype(auto) format20Numbers(int i, index_sequence< Indexes... >)
size_t uintToHexLower(char *buffer, size_t bufLen, Uint v)
Definition: Format-inl.h:90
size_t uintToOctal(char *buffer, size_t bufLen, Uint v)
Definition: Format-inl.h:112
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
void runBenchmarks()
Definition: Benchmark.cpp:456
const size_t kMaxHexLength
Definition: Format-inl.h:51
void init(int *argc, char ***argv, bool removeFlags)
Definition: Init.cpp:34
char ** argv
make_integer_sequence< std::size_t, Size > make_index_sequence
Definition: Utility.h:209
BENCHMARK_RELATIVE(octal_uintToOctal, iters)
void toAppend(char value, Tgt *result)
Definition: Conv.h:406
BENCHMARK(fbFollyGlobalBenchmarkBaseline)
Definition: Benchmark.cpp:84
auto dismissing(F f) -> invoke_result_t< F >
Definition: Benchmark.h:130
const char * string
Definition: Conv.cpp:212
BENCHMARK_DRAW_LINE()
Formatter< false, Args... > format(StringPiece fmt, Args &&...args)
Definition: Format.h:271
int main(int argc, char *argv[])
basic_fbstring & append(const basic_fbstring &str)
Definition: FBString.h:1953
const size_t kMaxOctalLength
Definition: Format-inl.h:52