2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/Format.h>
19 #include <glog/logging.h>
21 #include <folly/Benchmark.h>
22 #include <folly/FBVector.h>
23 #include <folly/dynamic.h>
24 #include <folly/init/Init.h>
25 #include <folly/json.h>
27 using namespace folly;
31 std::array<char, 300> bigBuf;
33 std::string getShortString() {
37 std::string getLongString() {
38 return std::string(256, 'A');
43 BENCHMARK(octal_snprintf, iters) {
46 bigBuf.data(), bigBuf.size(), "%o", static_cast<unsigned int>(iters));
50 BENCHMARK_RELATIVE(octal_uintToOctal, iters) {
54 detail::kMaxOctalLength,
55 static_cast<unsigned int>(iters));
61 BENCHMARK(hex_snprintf, iters) {
64 bigBuf.data(), bigBuf.size(), "%x", static_cast<unsigned int>(iters));
68 BENCHMARK_RELATIVE(hex_uintToHex, iters) {
70 detail::uintToHexLower(
71 bigBuf.data(), detail::kMaxHexLength, static_cast<unsigned int>(iters));
77 BENCHMARK(intAppend_snprintf) {
79 for (int i = -1000; i < 1000; i++) {
80 snprintf(bigBuf.data(), bigBuf.size(), "%d", i);
81 out.append(bigBuf.data());
85 BENCHMARK_RELATIVE(intAppend_to) {
87 for (int i = -1000; i < 1000; i++) {
92 BENCHMARK_RELATIVE(intAppend_format) {
94 for (int i = -1000; i < 1000; i++) {
95 format(&out, "{}", i);
101 template <size_t... Indexes>
102 int snprintf20Numbers(int i, std::index_sequence<Indexes...>) {
103 static_assert(20 == sizeof...(Indexes), "Must have exactly 20 indexes");
111 (i + static_cast<int>(Indexes))...);
114 BENCHMARK(bigFormat_snprintf, iters) {
116 for (int i = -100; i < 100; i++) {
117 snprintf20Numbers(i, std::make_index_sequence<20>());
122 template <size_t... Indexes>
123 decltype(auto) format20Numbers(int i, std::index_sequence<Indexes...>) {
124 static_assert(20 == sizeof...(Indexes), "Must have exactly 20 indexes");
130 (i + static_cast<int>(Indexes))...);
133 BENCHMARK_RELATIVE(bigFormat_format, iters) {
134 BenchmarkSuspender suspender;
136 auto writeToBuf = [&p](StringPiece sp) mutable {
137 memcpy(p, sp.data(), sp.size());
142 for (int i = -100; i < 100; i++) {
144 suspender.dismissing([&] {
145 format20Numbers(i, std::make_index_sequence<20>())(writeToBuf);
151 BENCHMARK_DRAW_LINE()
153 BENCHMARK(format_nested_strings, iters) {
154 BenchmarkSuspender suspender;
156 for (int i = 0; i < 1000; ++i) {
158 suspender.dismissing([&] {
162 format("{} {}", i, i + 1).str(),
163 format("{} {}", -i, -i - 1).str());
169 BENCHMARK_RELATIVE(format_nested_fbstrings, iters) {
170 BenchmarkSuspender suspender;
172 for (int i = 0; i < 1000; ++i) {
174 suspender.dismissing([&] {
178 format("{} {}", i, i + 1).fbstr(),
179 format("{} {}", -i, -i - 1).fbstr());
185 BENCHMARK_RELATIVE(format_nested_direct, iters) {
186 BenchmarkSuspender suspender;
188 for (int i = 0; i < 1000; ++i) {
190 suspender.dismissing([&] {
194 format("{} {}", i, i + 1),
195 format("{} {}", -i, -i - 1));
201 BENCHMARK_DRAW_LINE()
203 BENCHMARK(copy_short_string, iters) {
204 BenchmarkSuspender suspender;
205 auto const& shortString = getShortString();
208 suspender.dismissing([&] { out = shortString; });
212 BENCHMARK_RELATIVE(format_short_string_unsafe, iters) {
213 BenchmarkSuspender suspender;
214 auto const& shortString = getShortString();
217 suspender.dismissing([&] { format(&out, shortString); });
221 BENCHMARK_RELATIVE(format_short_string_safe, iters) {
222 BenchmarkSuspender suspender;
223 auto const& shortString = getShortString();
226 suspender.dismissing([&] { format(&out, "{}", shortString); });
230 BENCHMARK_RELATIVE(sformat_short_string_unsafe, iters) {
231 BenchmarkSuspender suspender;
232 auto const& shortString = getShortString();
235 suspender.dismissing([&] { out = sformat(shortString); });
239 BENCHMARK_RELATIVE(sformat_short_string_safe, iters) {
240 BenchmarkSuspender suspender;
241 auto const& shortString = getShortString();
244 suspender.dismissing([&] { out = sformat("{}", shortString); });
248 BENCHMARK_DRAW_LINE()
250 BENCHMARK(copy_long_string, iters) {
251 BenchmarkSuspender suspender;
252 auto const& longString = getLongString();
255 suspender.dismissing([&] { out = longString; });
259 BENCHMARK_RELATIVE(format_long_string_unsafe, iters) {
260 BenchmarkSuspender suspender;
261 auto const& longString = getLongString();
264 suspender.dismissing([&] { format(&out, longString); });
268 BENCHMARK_RELATIVE(format_long_string_safe, iters) {
269 BenchmarkSuspender suspender;
270 auto const& longString = getLongString();
273 suspender.dismissing([&] { format(&out, "{}", longString); });
277 BENCHMARK_RELATIVE(sformat_long_string_unsafe, iters) {
278 BenchmarkSuspender suspender;
279 auto const& longString = getLongString();
282 suspender.dismissing([&] { out = sformat(longString); });
286 BENCHMARK_RELATIVE(sformat_long_string_safe, iters) {
287 BenchmarkSuspender suspender;
288 auto const& longString = getLongString();
291 suspender.dismissing([&] { out = sformat("{}", longString); });
295 // Benchmark results on my dev server (20-core Intel Xeon E5-2660 v2 @ 2.20GHz)
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 // ============================================================================
330 int main(int argc, char* argv[]) {
331 init(&argc, &argv, true);