/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include FOLLY_GNU_DISABLE_WARNING("-Wdeprecated-declarations") using namespace folly; namespace { std::array bigBuf; std::string getShortString() { return "ABCDEFGHIJ"; } std::string getLongString() { return std::string(256, 'A'); } } // namespace BENCHMARK(octal_snprintf, iters) { while (iters--) { snprintf( bigBuf.data(), bigBuf.size(), "%o", static_cast(iters)); } } BENCHMARK_RELATIVE(octal_uintToOctal, iters) { while (iters--) { detail::uintToOctal( bigBuf.data(), detail::kMaxOctalLength, static_cast(iters)); } } BENCHMARK_DRAW_LINE(); BENCHMARK(hex_snprintf, iters) { while (iters--) { snprintf( bigBuf.data(), bigBuf.size(), "%x", static_cast(iters)); } } BENCHMARK_RELATIVE(hex_uintToHex, iters) { while (iters--) { detail::uintToHexLower( bigBuf.data(), detail::kMaxHexLength, static_cast(iters)); } } BENCHMARK_DRAW_LINE(); BENCHMARK(intAppend_snprintf) { fbstring out; for (int i = -1000; i < 1000; i++) { snprintf(bigBuf.data(), bigBuf.size(), "%d", i); out.append(bigBuf.data()); } } BENCHMARK_RELATIVE(intAppend_to) { fbstring out; for (int i = -1000; i < 1000; i++) { toAppend(i, &out); } } BENCHMARK_RELATIVE(intAppend_format) { fbstring out; for (int i = -1000; i < 1000; i++) { format(&out, "{}", i); } } BENCHMARK_DRAW_LINE(); template int snprintf20Numbers(int i, std::index_sequence) { static_assert(20 == sizeof...(Indexes), "Must have exactly 20 indexes"); return snprintf( bigBuf.data(), bigBuf.size(), "%d %d %d %d %d" "%d %d %d %d %d" "%d %d %d %d %d" "%d %d %d %d %d", (i + static_cast(Indexes))...); } BENCHMARK(bigFormat_snprintf, iters) { while (iters--) { for (int i = -100; i < 100; i++) { snprintf20Numbers(i, std::make_index_sequence<20>()); } } } template decltype(auto) format20Numbers(int i, std::index_sequence) { static_assert(20 == sizeof...(Indexes), "Must have exactly 20 indexes"); return format( "{} {} {} {} {}" "{} {} {} {} {}" "{} {} {} {} {}" "{} {} {} {} {}", (i + static_cast(Indexes))...); } BENCHMARK_RELATIVE(bigFormat_format, iters) { BenchmarkSuspender suspender; char* p; auto writeToBuf = [&p](StringPiece sp) mutable { memcpy(p, sp.data(), sp.size()); p += sp.size(); }; while (iters--) { for (int i = -100; i < 100; i++) { p = bigBuf.data(); suspender.dismissing([&] { format20Numbers(i, std::make_index_sequence<20>())(writeToBuf); }); } } } BENCHMARK_DRAW_LINE(); BENCHMARK(format_nested_strings, iters) { BenchmarkSuspender suspender; while (iters--) { for (int i = 0; i < 1000; ++i) { fbstring out; suspender.dismissing([&] { format( &out, "{} {}", sformat("{} {}", i, i + 1), sformat("{} {}", -i, -i - 1)); }); } } } BENCHMARK_RELATIVE(format_nested_direct, iters) { BenchmarkSuspender suspender; while (iters--) { for (int i = 0; i < 1000; ++i) { fbstring out; suspender.dismissing([&] { format( &out, "{} {}", format("{} {}", i, i + 1), format("{} {}", -i, -i - 1)); }); } } } BENCHMARK_DRAW_LINE(); BENCHMARK(copy_short_string, iters) { BenchmarkSuspender suspender; auto const& shortString = getShortString(); while (iters--) { fbstring out; suspender.dismissing([&] { out = shortString; }); } } BENCHMARK_RELATIVE(format_short_string_unsafe, iters) { BenchmarkSuspender suspender; auto const& shortString = getShortString(); while (iters--) { fbstring out; suspender.dismissing([&] { format(&out, shortString); }); } } BENCHMARK_RELATIVE(format_short_string_safe, iters) { BenchmarkSuspender suspender; auto const& shortString = getShortString(); while (iters--) { fbstring out; suspender.dismissing([&] { format(&out, "{}", shortString); }); } } BENCHMARK_RELATIVE(sformat_short_string_unsafe, iters) { BenchmarkSuspender suspender; auto const& shortString = getShortString(); while (iters--) { std::string out; suspender.dismissing([&] { out = sformat(shortString); }); } } BENCHMARK_RELATIVE(sformat_short_string_safe, iters) { BenchmarkSuspender suspender; auto const& shortString = getShortString(); while (iters--) { std::string out; suspender.dismissing([&] { out = sformat("{}", shortString); }); } } BENCHMARK_DRAW_LINE(); BENCHMARK(copy_long_string, iters) { BenchmarkSuspender suspender; auto const& longString = getLongString(); while (iters--) { fbstring out; suspender.dismissing([&] { out = longString; }); } } BENCHMARK_RELATIVE(format_long_string_unsafe, iters) { BenchmarkSuspender suspender; auto const& longString = getLongString(); while (iters--) { fbstring out; suspender.dismissing([&] { format(&out, longString); }); } } BENCHMARK_RELATIVE(format_long_string_safe, iters) { BenchmarkSuspender suspender; auto const& longString = getLongString(); while (iters--) { fbstring out; suspender.dismissing([&] { format(&out, "{}", longString); }); } } BENCHMARK_RELATIVE(sformat_long_string_unsafe, iters) { BenchmarkSuspender suspender; auto const& longString = getLongString(); while (iters--) { std::string out; suspender.dismissing([&] { out = sformat(longString); }); } } BENCHMARK_RELATIVE(sformat_long_string_safe, iters) { BenchmarkSuspender suspender; auto const& longString = getLongString(); while (iters--) { std::string out; suspender.dismissing([&] { out = sformat("{}", longString); }); } } // Benchmark results on my dev server (20-core Intel Xeon E5-2660 v2 @ 2.20GHz) // // ============================================================================ // folly/test/FormatBenchmark.cpp relative time/iter iters/s // ============================================================================ // octal_snprintf 79.30ns 12.61M // octal_uintToOctal 3452.19% 2.30ns 435.35M // ---------------------------------------------------------------------------- // hex_snprintf 73.59ns 13.59M // hex_uintToHex 4507.53% 1.63ns 612.49M // ---------------------------------------------------------------------------- // intAppend_snprintf 191.50us 5.22K // intAppend_to 552.46% 34.66us 28.85K // intAppend_format 215.76% 88.76us 11.27K // ---------------------------------------------------------------------------- // bigFormat_snprintf 178.03us 5.62K // bigFormat_format 90.41% 196.91us 5.08K // ---------------------------------------------------------------------------- // format_nested_strings 317.65us 3.15K // format_nested_direct 116.52% 272.62us 3.67K // ---------------------------------------------------------------------------- // copy_short_string 28.33ns 35.30M // format_short_string_unsafe 82.51% 34.33ns 29.13M // format_short_string_safe 58.92% 48.08ns 20.80M // sformat_short_string_unsafe 73.90% 38.33ns 26.09M // sformat_short_string_safe 54.97% 51.53ns 19.41M // ---------------------------------------------------------------------------- // copy_long_string 57.56ns 17.37M // format_long_string_unsafe 68.79% 83.68ns 11.95M // format_long_string_safe 69.44% 82.89ns 12.06M // sformat_long_string_unsafe 65.58% 87.77ns 11.39M // sformat_long_string_safe 68.14% 84.47ns 11.84M // ============================================================================ int main(int argc, char* argv[]) { folly::Init init(&argc, &argv, true); runBenchmarks(); return 0; }