From: Tom Jackson Date: Fri, 18 Nov 2016 02:14:14 +0000 (-0800) Subject: Faster unhexlify X-Git-Tag: v2016.11.21.00~12 X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=ace896f3443632b94fdad46cb5104a377cd5e4fe;p=folly.git Faster unhexlify Summary: Using already-available lookup table instead of a bunch of branching, this improves read throughput from ~750MB/s to 2.1GB/s in benchmarks. ``` before: (time) (rate) BM_unhexlify 1.39ns 719.26M after: BM_unhexlify 470.59ps 2.13G ``` Reviewed By: philippv Differential Revision: D4201352 fbshipit-source-id: 8393e066c45c402ccb8b537fdb25417e8e6a9511 --- diff --git a/folly/String-inl.h b/folly/String-inl.h index 2bf0104a..1732b50c 100644 --- a/folly/String-inl.h +++ b/folly/String-inl.h @@ -587,17 +587,12 @@ bool unhexlify(const InputString& input, OutputString& output) { } output.resize(input.size() / 2); int j = 0; - auto unhex = [](char c) -> int { - return c >= '0' && c <= '9' ? c - '0' : - c >= 'A' && c <= 'F' ? c - 'A' + 10 : - c >= 'a' && c <= 'f' ? c - 'a' + 10 : - -1; - }; for (size_t i = 0; i < input.size(); i += 2) { - int highBits = unhex(input[i]); - int lowBits = unhex(input[i + 1]); - if (highBits < 0 || lowBits < 0) { + int highBits = detail::hexTable[static_cast(input[i])]; + int lowBits = detail::hexTable[static_cast(input[i + 1])]; + if ((highBits | lowBits) & 0x10) { + // One of the characters wasn't a hex digit return false; } output[j++] = (highBits << 4) + lowBits; diff --git a/folly/test/StringBenchmark.cpp b/folly/test/StringBenchmark.cpp index 67790d4d..d6b57161 100644 --- a/folly/test/StringBenchmark.cpp +++ b/folly/test/StringBenchmark.cpp @@ -17,8 +17,9 @@ #include #include -#include #include +#include +#include #include using namespace folly; @@ -102,6 +103,10 @@ fbstring uriUnescapedString; const size_t kURIBmStringLength = 256; const uint32_t kURIPassThroughPercentage = 50; +fbstring hexlifyInput; +fbstring hexlifyOutput; +const size_t kHexlifyLength = 1024; + void initBenchmark() { std::mt19937 rnd; @@ -145,6 +150,11 @@ void initBenchmark() { } uribmEscapedString = uriEscape(uribmString); + + // hexlify + hexlifyInput.resize(kHexlifyLength); + Random::secureRandom(&hexlifyInput[0], kHexlifyLength); + folly::hexlify(hexlifyInput, hexlifyOutput); } BENCHMARK(BM_cEscape, iters) { @@ -175,6 +185,18 @@ BENCHMARK(BM_uriUnescape, iters) { } } +BENCHMARK(BM_unhexlify, iters) { + // iters/sec = bytes output per sec + std::string unhexed; + folly::StringPiece hex = hexlifyOutput; + for (; iters >= hex.size(); iters -= hex.size()) { + folly::unhexlify(hex, unhexed); + } + iters -= iters % 2; // round down to an even number of chars + hex = hex.subpiece(0, iters); + folly::unhexlify(hex, unhexed); +} + } // namespace //////////////////////////////////////////////////////////////////////