From: Michael Lee Date: Wed, 20 Jan 2016 15:10:31 +0000 (-0800) Subject: Move StringTest benchmarks into StringBenchmark.cpp X-Git-Tag: deprecate-dynamic-initializer~149 X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=commitdiff_plain;h=f00612cfebc7082dac3aba6a47f7ba93af2951ec Move StringTest benchmarks into StringBenchmark.cpp Summary: StringTest.cpp is a mix of benchmarks and normal unittests. Fixing this. Reviewed By: yfeldblum Differential Revision: D2840804 fb-gh-sync-id: d3efc357f5f09385e9f69b70e38b64d59045ff0d --- diff --git a/folly/test/Makefile.am b/folly/test/Makefile.am index 7c277e19..c9dec173 100644 --- a/folly/test/Makefile.am +++ b/folly/test/Makefile.am @@ -149,7 +149,7 @@ map_util_test_LDADD = libgtestmain.la $(top_builddir)/libfolly.la TESTS += map_util_test string_test_SOURCES = StringTest.cpp -string_test_LDADD = libgtest.la $(top_builddir)/libfolly.la $(top_builddir)/libfollybenchmark.la +string_test_LDADD = libgtest.la $(top_builddir)/libfolly.la TESTS += string_test producer_consumer_queue_test_SOURCES = ProducerConsumerQueueTest.cpp diff --git a/folly/test/StringBenchmark.cpp b/folly/test/StringBenchmark.cpp index c9c90d7d..dfcd47eb 100644 --- a/folly/test/StringBenchmark.cpp +++ b/folly/test/StringBenchmark.cpp @@ -14,9 +14,16 @@ * limitations under the License. */ -#include #include +#include +#include +#include +#include + +using namespace folly; +using namespace std; + BENCHMARK(libc_tolower, iters) { static const size_t kSize = 256; // This array is static to keep the compiler from optimizing the @@ -47,12 +54,210 @@ BENCHMARK(folly_toLowerAscii, iters) { } } +// A simple benchmark that tests various output sizes for a simple +// input; the goal is to measure the output buffer resize code cost. +void stringPrintfOutputSize(int iters, int param) { + string buffer; + BENCHMARK_SUSPEND { buffer.resize(param, 'x'); } + + for (int64_t i = 0; i < iters; ++i) { + string s = stringPrintf("msg: %d, %d, %s", 10, 20, buffer.c_str()); + } +} + +// The first few of these tend to fit in the inline buffer, while the +// subsequent ones cross that limit, trigger a second vsnprintf, and +// exercise a different codepath. +BENCHMARK_PARAM(stringPrintfOutputSize, 1) +BENCHMARK_PARAM(stringPrintfOutputSize, 4) +BENCHMARK_PARAM(stringPrintfOutputSize, 16) +BENCHMARK_PARAM(stringPrintfOutputSize, 64) +BENCHMARK_PARAM(stringPrintfOutputSize, 256) +BENCHMARK_PARAM(stringPrintfOutputSize, 1024) + +// Benchmark simple stringAppendf behavior to show a pathology Lovro +// reported (t5735468). +BENCHMARK(stringPrintfAppendfBenchmark, iters) { + for (unsigned int i = 0; i < iters; ++i) { + string s; + BENCHMARK_SUSPEND { s.reserve(300000); } + for (int j = 0; j < 300000; ++j) { + stringAppendf(&s, "%d", 1); + } + } +} + +namespace { +fbstring cbmString; +fbstring cbmEscapedString; +fbstring cEscapedString; +fbstring cUnescapedString; +const size_t kCBmStringLength = 64 << 10; +const uint32_t kCPrintablePercentage = 90; + +fbstring uribmString; +fbstring uribmEscapedString; +fbstring uriEscapedString; +fbstring uriUnescapedString; +const size_t kURIBmStringLength = 256; +const uint32_t kURIPassThroughPercentage = 50; + +void initBenchmark() { + std::mt19937 rnd; + + // C escape + std::uniform_int_distribution printable(32, 126); + std::uniform_int_distribution nonPrintable(0, 160); + std::uniform_int_distribution percentage(0, 99); + + cbmString.reserve(kCBmStringLength); + for (size_t i = 0; i < kCBmStringLength; ++i) { + unsigned char c; + if (percentage(rnd) < kCPrintablePercentage) { + c = printable(rnd); + } else { + c = nonPrintable(rnd); + // Generate characters in both non-printable ranges: + // 0..31 and 127..255 + if (c >= 32) { + c += (126 - 32) + 1; + } + } + cbmString.push_back(c); + } + + cbmEscapedString = cEscape(cbmString); + + // URI escape + std::uniform_int_distribution passthrough('a', 'z'); + std::string encodeChars = " ?!\"',+[]"; + std::uniform_int_distribution encode(0, encodeChars.size() - 1); + + uribmString.reserve(kURIBmStringLength); + for (size_t i = 0; i < kURIBmStringLength; ++i) { + unsigned char c; + if (percentage(rnd) < kURIPassThroughPercentage) { + c = passthrough(rnd); + } else { + c = encodeChars[encode(rnd)]; + } + uribmString.push_back(c); + } + + uribmEscapedString = uriEscape(uribmString); +} + +BENCHMARK(BM_cEscape, iters) { + while (iters--) { + cEscapedString = cEscape(cbmString); + doNotOptimizeAway(cEscapedString.size()); + } +} + +BENCHMARK(BM_cUnescape, iters) { + while (iters--) { + cUnescapedString = cUnescape(cbmEscapedString); + doNotOptimizeAway(cUnescapedString.size()); + } +} + +BENCHMARK(BM_uriEscape, iters) { + while (iters--) { + uriEscapedString = uriEscape(uribmString); + doNotOptimizeAway(uriEscapedString.size()); + } +} + +BENCHMARK(BM_uriUnescape, iters) { + while (iters--) { + uriUnescapedString = uriUnescape(uribmEscapedString); + doNotOptimizeAway(uriUnescapedString.size()); + } +} + +} // namespace + +////////////////////////////////////////////////////////////////////// + +BENCHMARK(splitOnSingleChar, iters) { + static const std::string line = "one:two:three:four"; + for (size_t i = 0; i < iters << 4; ++i) { + std::vector pieces; + folly::split(':', line, pieces); + } +} + +BENCHMARK(splitOnSingleCharFixed, iters) { + static const std::string line = "one:two:three:four"; + for (size_t i = 0; i < iters << 4; ++i) { + StringPiece a, b, c, d; + folly::split(':', line, a, b, c, d); + } +} + +BENCHMARK(splitOnSingleCharFixedAllowExtra, iters) { + static const std::string line = "one:two:three:four"; + for (size_t i = 0; i < iters << 4; ++i) { + StringPiece a, b, c, d; + folly::split(':', line, a, b, c, d); + } +} + +BENCHMARK(splitStr, iters) { + static const std::string line = "one-*-two-*-three-*-four"; + for (size_t i = 0; i < iters << 4; ++i) { + std::vector pieces; + folly::split("-*-", line, pieces); + } +} + +BENCHMARK(splitStrFixed, iters) { + static const std::string line = "one-*-two-*-three-*-four"; + for (size_t i = 0; i < iters << 4; ++i) { + StringPiece a, b, c, d; + folly::split("-*-", line, a, b, c, d); + } +} + +BENCHMARK(boost_splitOnSingleChar, iters) { + static const std::string line = "one:two:three:four"; + bool (*pred)(char) = [](char c) -> bool { return c == ':'; }; + for (size_t i = 0; i < iters << 4; ++i) { + std::vector> pieces; + boost::split(pieces, line, pred); + } +} + +BENCHMARK(joinCharStr, iters) { + static const std::vector input = { + "one", "two", "three", "four", "five", "six", "seven"}; + for (size_t i = 0; i < iters << 4; ++i) { + std::string output; + folly::join(':', input, output); + } +} + +BENCHMARK(joinStrStr, iters) { + static const std::vector input = { + "one", "two", "three", "four", "five", "six", "seven"}; + for (size_t i = 0; i < iters << 4; ++i) { + std::string output; + folly::join(":", input, output); + } +} + +BENCHMARK(joinInt, iters) { + static const auto input = {123, 456, 78910, 1112, 1314, 151, 61718}; + for (size_t i = 0; i < iters << 4; ++i) { + std::string output; + folly::join(":", input, output); + } +} + int main(int argc, char** argv) { gflags::ParseCommandLineFlags(&argc, &argv, true); + initBenchmark(); folly::runBenchmarks(); - if (FLAGS_benchmark) { - folly::runBenchmarks(); - } return 0; } @@ -61,7 +266,27 @@ Results on x86_64: ============================================================================ folly/test/StringBenchmark.cpp relative time/iter iters/s ============================================================================ -libc_tolower 1.30us 767.50K -folly_toLowerAscii 115.21ns 8.68M +libc_tolower 773.30ns 1.29M +folly_toLowerAscii 65.04ns 15.38M +stringPrintfOutputSize(1) 224.67ns 4.45M +stringPrintfOutputSize(4) 231.53ns 4.32M +stringPrintfOutputSize(16) 286.54ns 3.49M +stringPrintfOutputSize(64) 305.47ns 3.27M +stringPrintfOutputSize(256) 1.48us 674.45K +stringPrintfOutputSize(1024) 5.89us 169.72K +stringPrintfAppendfBenchmark 34.43ms 29.04 +BM_cEscape 461.51us 2.17K +BM_cUnescape 328.19us 3.05K +BM_uriEscape 4.36us 229.25K +BM_uriUnescape 2.22us 450.64K +splitOnSingleChar 1.46us 687.21K +splitOnSingleCharFixed 133.02ns 7.52M +splitOnSingleCharFixedAllowExtra 74.35ns 13.45M +splitStr 2.36us 424.00K +splitStrFixed 282.38ns 3.54M +boost_splitOnSingleChar 2.83us 353.12K +joinCharStr 2.65us 376.93K +joinStrStr 2.64us 378.09K +joinInt 3.89us 257.37K ============================================================================ */ diff --git a/folly/test/StringTest.cpp b/folly/test/StringTest.cpp index 526afeec..759c4477 100644 --- a/folly/test/StringTest.cpp +++ b/folly/test/StringTest.cpp @@ -16,13 +16,8 @@ #include -#include -#include -#include #include -#include - using namespace folly; using namespace std; @@ -155,39 +150,6 @@ TEST(StringPrintf, oldStringAppendf) { EXPECT_EQ(string("helloa/b/c/d"), s); } -// A simple benchmark that tests various output sizes for a simple -// input; the goal is to measure the output buffer resize code cost. -void stringPrintfOutputSize(int iters, int param) { - string buffer; - BENCHMARK_SUSPEND { buffer.resize(param, 'x'); } - - for (int64_t i = 0; i < iters; ++i) { - string s = stringPrintf("msg: %d, %d, %s", 10, 20, buffer.c_str()); - } -} - -// The first few of these tend to fit in the inline buffer, while the -// subsequent ones cross that limit, trigger a second vsnprintf, and -// exercise a different codepath. -BENCHMARK_PARAM(stringPrintfOutputSize, 1) -BENCHMARK_PARAM(stringPrintfOutputSize, 4) -BENCHMARK_PARAM(stringPrintfOutputSize, 16) -BENCHMARK_PARAM(stringPrintfOutputSize, 64) -BENCHMARK_PARAM(stringPrintfOutputSize, 256) -BENCHMARK_PARAM(stringPrintfOutputSize, 1024) - -// Benchmark simple stringAppendf behavior to show a pathology Lovro -// reported (t5735468). -BENCHMARK(stringPrintfAppendfBenchmark, iters) { - for (unsigned int i = 0; i < iters; ++i) { - string s; - BENCHMARK_SUSPEND { s.reserve(300000); } - for (int j = 0; j < 300000; ++j) { - stringAppendf(&s, "%d", 1); - } - } -} - TEST(Escape, cEscape) { EXPECT_EQ("hello world", cEscape("hello world")); EXPECT_EQ("hello \\\\world\\\" goodbye", @@ -303,96 +265,6 @@ TEST(Escape, uriUnescapePercentDecoding) { } } -namespace { -fbstring cbmString; -fbstring cbmEscapedString; -fbstring cEscapedString; -fbstring cUnescapedString; -const size_t kCBmStringLength = 64 << 10; -const uint32_t kCPrintablePercentage = 90; - -fbstring uribmString; -fbstring uribmEscapedString; -fbstring uriEscapedString; -fbstring uriUnescapedString; -const size_t kURIBmStringLength = 256; -const uint32_t kURIPassThroughPercentage = 50; - -void initBenchmark() { - std::mt19937 rnd; - - // C escape - std::uniform_int_distribution printable(32, 126); - std::uniform_int_distribution nonPrintable(0, 160); - std::uniform_int_distribution percentage(0, 99); - - cbmString.reserve(kCBmStringLength); - for (size_t i = 0; i < kCBmStringLength; ++i) { - unsigned char c; - if (percentage(rnd) < kCPrintablePercentage) { - c = printable(rnd); - } else { - c = nonPrintable(rnd); - // Generate characters in both non-printable ranges: - // 0..31 and 127..255 - if (c >= 32) { - c += (126 - 32) + 1; - } - } - cbmString.push_back(c); - } - - cbmEscapedString = cEscape(cbmString); - - // URI escape - std::uniform_int_distribution passthrough('a', 'z'); - std::string encodeChars = " ?!\"',+[]"; - std::uniform_int_distribution encode(0, encodeChars.size() - 1); - - uribmString.reserve(kURIBmStringLength); - for (size_t i = 0; i < kURIBmStringLength; ++i) { - unsigned char c; - if (percentage(rnd) < kURIPassThroughPercentage) { - c = passthrough(rnd); - } else { - c = encodeChars[encode(rnd)]; - } - uribmString.push_back(c); - } - - uribmEscapedString = uriEscape(uribmString); -} - -BENCHMARK(BM_cEscape, iters) { - while (iters--) { - cEscapedString = cEscape(cbmString); - doNotOptimizeAway(cEscapedString.size()); - } -} - -BENCHMARK(BM_cUnescape, iters) { - while (iters--) { - cUnescapedString = cUnescape(cbmEscapedString); - doNotOptimizeAway(cUnescapedString.size()); - } -} - -BENCHMARK(BM_uriEscape, iters) { - while (iters--) { - uriEscapedString = uriEscape(uribmString); - doNotOptimizeAway(uriEscapedString.size()); - } -} - -BENCHMARK(BM_uriUnescape, iters) { - while (iters--) { - uriUnescapedString = uriUnescape(uribmEscapedString); - doNotOptimizeAway(uriUnescapedString.size()); - } -} - -} // namespace - namespace { double pow2(int exponent) { @@ -1212,84 +1084,6 @@ TEST(String, toLowerAsciiUnaligned) { } } -////////////////////////////////////////////////////////////////////// - -BENCHMARK(splitOnSingleChar, iters) { - static const std::string line = "one:two:three:four"; - for (size_t i = 0; i < iters << 4; ++i) { - std::vector pieces; - folly::split(':', line, pieces); - } -} - -BENCHMARK(splitOnSingleCharFixed, iters) { - static const std::string line = "one:two:three:four"; - for (size_t i = 0; i < iters << 4; ++i) { - StringPiece a, b, c, d; - folly::split(':', line, a, b, c, d); - } -} - -BENCHMARK(splitOnSingleCharFixedAllowExtra, iters) { - static const std::string line = "one:two:three:four"; - for (size_t i = 0; i < iters << 4; ++i) { - StringPiece a, b, c, d; - folly::split(':', line, a, b, c, d); - } -} - -BENCHMARK(splitStr, iters) { - static const std::string line = "one-*-two-*-three-*-four"; - for (size_t i = 0; i < iters << 4; ++i) { - std::vector pieces; - folly::split("-*-", line, pieces); - } -} - -BENCHMARK(splitStrFixed, iters) { - static const std::string line = "one-*-two-*-three-*-four"; - for (size_t i = 0; i < iters << 4; ++i) { - StringPiece a, b, c, d; - folly::split("-*-", line, a, b, c, d); - } -} - -BENCHMARK(boost_splitOnSingleChar, iters) { - static const std::string line = "one:two:three:four"; - bool(*pred)(char) = [] (char c) -> bool { return c == ':'; }; - for (size_t i = 0; i < iters << 4; ++i) { - std::vector > pieces; - boost::split(pieces, line, pred); - } -} - -BENCHMARK(joinCharStr, iters) { - static const std::vector input = { - "one", "two", "three", "four", "five", "six", "seven" }; - for (size_t i = 0; i < iters << 4; ++i) { - std::string output; - folly::join(':', input, output); - } -} - -BENCHMARK(joinStrStr, iters) { - static const std::vector input = { - "one", "two", "three", "four", "five", "six", "seven" }; - for (size_t i = 0; i < iters << 4; ++i) { - std::string output; - folly::join(":", input, output); - } -} - -BENCHMARK(joinInt, iters) { - static const auto input = { - 123, 456, 78910, 1112, 1314, 151, 61718 }; - for (size_t i = 0; i < iters << 4; ++i) { - std::string output; - folly::join(":", input, output); - } -} - TEST(String, whitespace) { // trimWhitespace: EXPECT_EQ("kavabanga", @@ -1359,16 +1153,3 @@ TEST(UTF8StringPiece, empty_mid_codepoint) { TEST(UTF8StringPiece, invalid_mid_codepoint) { EXPECT_THROW(UTF8StringPiece(kTestUTF8.subpiece(9, 1)), std::out_of_range); } - -int main(int argc, char *argv[]) { - testing::InitGoogleTest(&argc, argv); - gflags::ParseCommandLineFlags(&argc, &argv, true); - auto ret = RUN_ALL_TESTS(); - if (!ret) { - initBenchmark(); - if (FLAGS_benchmark) { - folly::runBenchmarks(); - } - } - return ret; -}