Commit 96000632 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by facebook-github-bot-5

Support SSE-enabled Range functions under Clang

Summary: [Folly] Support SSE-enabled `Range` functions under Clang.

Basically, we remove GCC-only -isms. In particular, we use only names from the `<emmintrins.h>` and `<smmintrins.h>` headers, instead of the GCC-specific SSE builtins that the original code uses.

But in order to get this to work, we must split out the SSE-enabled functions into their own sources and compile them with the `-msse4.2` flag. There is a way to get around this in GCC by marking individual functions as SEE-enabled, but that technique is not supported in Clang. This is the new `RangeSse42` module.

And in order to do that, we must split out the code that is called by both the original `Range` and the new SSE-enabled functions into yet a third module, `RangeCommon`.

Ahhhhhh, dependencies.

Note that we always compile the SSE-enabled functions, but we only run them on architectures supporting SSE. The original code tests the CPU's capabilities before running any SSE-enabled functions; this change retains that check.

Reviewed By: @nbronson

Differential Revision: D2428983
parent b05969e4
...@@ -247,6 +247,8 @@ nobase_follyinclude_HEADERS = \ ...@@ -247,6 +247,8 @@ nobase_follyinclude_HEADERS = \
Random.h \ Random.h \
Random-inl.h \ Random-inl.h \
Range.h \ Range.h \
RangeCommon.h \
RangeSse42.h \
ReadMostlySharedPtr.h \ ReadMostlySharedPtr.h \
RWSpinLock.h \ RWSpinLock.h \
ScopeGuard.h \ ScopeGuard.h \
...@@ -308,6 +310,8 @@ libfollybase_la_SOURCES = \ ...@@ -308,6 +310,8 @@ libfollybase_la_SOURCES = \
FormatTables.cpp \ FormatTables.cpp \
Malloc.cpp \ Malloc.cpp \
Range.cpp \ Range.cpp \
RangeCommon.cpp \
RangeSse42.cpp \
StringBase.cpp \ StringBase.cpp \
String.cpp \ String.cpp \
Unicode.cpp Unicode.cpp
......
...@@ -48,6 +48,8 @@ ...@@ -48,6 +48,8 @@
#include <folly/CpuId.h> #include <folly/CpuId.h>
#include <folly/Traits.h> #include <folly/Traits.h>
#include <folly/Likely.h> #include <folly/Likely.h>
#include <folly/detail/RangeCommon.h>
#include <folly/detail/RangeSse42.h>
// Ignore shadowing warnings within this file, so includers can use -Wshadow. // Ignore shadowing warnings within this file, so includers can use -Wshadow.
#pragma GCC diagnostic push #pragma GCC diagnostic push
...@@ -1000,13 +1002,6 @@ size_t qfind(const Range<T>& haystack, ...@@ -1000,13 +1002,6 @@ size_t qfind(const Range<T>& haystack,
namespace detail { namespace detail {
size_t qfind_first_byte_of_nosse(const StringPiece haystack,
const StringPiece needles);
#if FOLLY_HAVE_EMMINTRIN_H && __GNUC_PREREQ(4, 6)
size_t qfind_first_byte_of_sse42(const StringPiece haystack,
const StringPiece needles);
inline size_t qfind_first_byte_of(const StringPiece haystack, inline size_t qfind_first_byte_of(const StringPiece haystack,
const StringPiece needles) { const StringPiece needles) {
static auto const qfind_first_byte_of_fn = static auto const qfind_first_byte_of_fn =
...@@ -1015,13 +1010,6 @@ inline size_t qfind_first_byte_of(const StringPiece haystack, ...@@ -1015,13 +1010,6 @@ inline size_t qfind_first_byte_of(const StringPiece haystack,
return qfind_first_byte_of_fn(haystack, needles); return qfind_first_byte_of_fn(haystack, needles);
} }
#else
inline size_t qfind_first_byte_of(const StringPiece haystack,
const StringPiece needles) {
return qfind_first_byte_of_nosse(haystack, needles);
}
#endif // FOLLY_HAVE_EMMINTRIN_H
} // namespace detail } // namespace detail
template <class T, class Comp> template <class T, class Comp>
......
...@@ -120,7 +120,7 @@ AM_PATH_PYTHON ...@@ -120,7 +120,7 @@ AM_PATH_PYTHON
# Checks for header files. # Checks for header files.
AC_HEADER_STDC AC_HEADER_STDC
AC_CHECK_HEADERS([fcntl.h features.h inttypes.h limits.h stdint.h stdlib.h string.h sys/time.h unistd.h mutex.h malloc.h emmintrin.h byteswap.h bits/functexcept.h bits/c++config.h]) AC_CHECK_HEADERS([fcntl.h features.h inttypes.h limits.h stdint.h stdlib.h string.h sys/time.h unistd.h mutex.h malloc.h byteswap.h bits/functexcept.h bits/c++config.h])
AC_CHECK_HEADER(double-conversion/double-conversion.h, [], [AC_MSG_ERROR( AC_CHECK_HEADER(double-conversion/double-conversion.h, [], [AC_MSG_ERROR(
[Couldn't find double-conversion.h, please download from \ [Couldn't find double-conversion.h, please download from \
......
/*
* Copyright 2015 Facebook, Inc.
*
* 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 <folly/detail/RangeCommon.h>
#include <bitset>
#include <folly/SparseByteSet.h>
namespace folly {
namespace detail {
size_t qfind_first_byte_of_bitset(const StringPieceLite haystack,
const StringPieceLite needles) {
std::bitset<256> s;
for (auto needle : needles) {
s[(uint8_t)needle] = true;
}
for (size_t index = 0; index < haystack.size(); ++index) {
if (s[(uint8_t)haystack[index]]) {
return index;
}
}
return std::string::npos;
}
size_t qfind_first_byte_of_byteset(const StringPieceLite haystack,
const StringPieceLite needles) {
SparseByteSet s;
for (auto needle: needles) {
s.add(needle);
}
for (size_t index = 0; index < haystack.size(); ++index) {
if (s.contains(haystack[index])) {
return index;
}
}
return std::string::npos;
}
}
}
/*
* Copyright 2015 Facebook, Inc.
*
* 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.
*/
#ifndef FOLLY_DETAIL_RANGE_COMMON_H_
#define FOLLY_DETAIL_RANGE_COMMON_H_
#include <algorithm>
#include <string>
#include <glog/logging.h>
#include <folly/Likely.h>
namespace folly {
namespace detail {
/***
* The qfind_first_byte_of_* functions are declared here, before Range.h, so
* they cannot take StringPiece values. But they're there to operate on
* StringPiece values. Dependency cycles: fun.
*
* StringPieceLite is here to break that dependency cycle.
*/
class StringPieceLite {
public:
StringPieceLite(const char* b, const char* e) : b_(b), e_(e) {}
template <typename Range>
/* implicit */ StringPieceLite(const Range& r) :
StringPieceLite(r.data(), r.data() + r.size()) {}
const char* data() const { return b_; }
const char* begin() const { return b_; }
const char* end() const { return e_; }
size_t size() const { return e_ - b_; }
bool empty() const { return size() == 0; }
const char& operator[](size_t i) const { DCHECK_GT(size(), i); return b_[i]; }
template <typename Range>
explicit operator Range() const { return Range(begin(), end()); }
private:
const char* b_;
const char* e_;
};
inline size_t qfind_first_byte_of_std(const StringPieceLite haystack,
const StringPieceLite needles) {
auto ret = std::find_first_of(haystack.begin(), haystack.end(),
needles.begin(), needles.end(),
[](char a, char b) { return a == b; });
return ret == haystack.end() ? std::string::npos : ret - haystack.begin();
}
size_t qfind_first_byte_of_bitset(const StringPieceLite haystack,
const StringPieceLite needles);
size_t qfind_first_byte_of_byteset(const StringPieceLite haystack,
const StringPieceLite needles);
inline size_t qfind_first_byte_of_nosse(const StringPieceLite haystack,
const StringPieceLite needles) {
if (UNLIKELY(needles.empty() || haystack.empty())) {
return std::string::npos;
}
// The thresholds below were empirically determined by benchmarking.
// This is not an exact science since it depends on the CPU, the size of
// needles, and the size of haystack.
if ((needles.size() >= 4 && haystack.size() <= 10) ||
(needles.size() >= 16 && haystack.size() <= 64) ||
needles.size() >= 32) {
return qfind_first_byte_of_byteset(haystack, needles);
}
return qfind_first_byte_of_std(haystack, needles);
}
}
}
#endif
...@@ -14,67 +14,65 @@ ...@@ -14,67 +14,65 @@
* limitations under the License. * limitations under the License.
*/ */
// @author Mark Rabkin (mrabkin@fb.com) #include "RangeSse42.h"
// @author Andrei Alexandrescu (andrei.alexandrescu@fb.com)
#include <folly/Range.h> #include <cstdint>
#include <folly/SparseByteSet.h> #include <limits>
#include <string>
#if FOLLY_HAVE_EMMINTRIN_H #include <emmintrin.h>
#include <emmintrin.h> // __v16qi #include <smmintrin.h>
#endif #include <glog/logging.h>
#include <bitset> #include <folly/Likely.h>
#include <iostream> #include <folly/Portability.h>
namespace folly { namespace folly {
namespace { namespace detail {
// It's okay if pages are bigger than this (as powers of two), but they should // It's okay if pages are bigger than this (as powers of two), but they should
// not be smaller. // not be smaller.
constexpr size_t kMinPageSize = 4096; static constexpr size_t kMinPageSize = 4096;
static_assert(kMinPageSize >= 16, static_assert(kMinPageSize >= 16,
"kMinPageSize must be at least SSE register size"); "kMinPageSize must be at least SSE register size");
#define PAGE_FOR(addr) \
(reinterpret_cast<uintptr_t>(addr) / kMinPageSize)
template <typename T>
static inline uintptr_t page_for(T* addr) {
return reinterpret_cast<uintptr_t>(addr) / kMinPageSize;
}
// Earlier versions of GCC (for example, Clang on Mac OS X, which is based on static inline size_t nextAlignedIndex(const char* arr) {
// GCC 4.2) do not have a full compliment of SSE builtins.
#if FOLLY_HAVE_EMMINTRIN_H && __GNUC_PREREQ(4, 6)
inline size_t nextAlignedIndex(const char* arr) {
auto firstPossible = reinterpret_cast<uintptr_t>(arr) + 1; auto firstPossible = reinterpret_cast<uintptr_t>(arr) + 1;
return 1 + // add 1 because the index starts at 'arr' return 1 + // add 1 because the index starts at 'arr'
((firstPossible + 15) & ~0xF) // round up to next multiple of 16 ((firstPossible + 15) & ~0xF) // round up to next multiple of 16
- firstPossible; - firstPossible;
} }
// build sse4.2-optimized version even if -msse4.2 is not passed to GCC static size_t qfind_first_byte_of_needles16(const StringPieceLite haystack,
size_t qfind_first_byte_of_needles16(const StringPiece haystack, const StringPieceLite needles)
const StringPiece needles)
__attribute__ ((__target__("sse4.2"), noinline))
FOLLY_DISABLE_ADDRESS_SANITIZER; FOLLY_DISABLE_ADDRESS_SANITIZER;
// helper method for case where needles.size() <= 16 // helper method for case where needles.size() <= 16
size_t qfind_first_byte_of_needles16(const StringPiece haystack, size_t qfind_first_byte_of_needles16(const StringPieceLite haystack,
const StringPiece needles) { const StringPieceLite needles) {
DCHECK(!haystack.empty()); DCHECK_GT(haystack.size(), 0);
DCHECK(!needles.empty()); DCHECK_GT(needles.size(), 0);
DCHECK_LE(needles.size(), 16); DCHECK_LE(needles.size(), 16);
if ((needles.size() <= 2 && haystack.size() >= 256) || if ((needles.size() <= 2 && haystack.size() >= 256) ||
// must bail if we can't even SSE-load a single segment of haystack // must bail if we can't even SSE-load a single segment of haystack
(haystack.size() < 16 && (haystack.size() < 16 &&
PAGE_FOR(haystack.end() - 1) != PAGE_FOR(haystack.data() + 15)) || page_for(haystack.end() - 1) != page_for(haystack.data() + 15)) ||
// can't load needles into SSE register if it could cross page boundary // can't load needles into SSE register if it could cross page boundary
PAGE_FOR(needles.end() - 1) != PAGE_FOR(needles.data() + 15)) { page_for(needles.end() - 1) != page_for(needles.data() + 15)) {
return detail::qfind_first_byte_of_nosse(haystack, needles); return detail::qfind_first_byte_of_nosse(haystack, needles);
} }
auto arr2 = __builtin_ia32_loaddqu(needles.data()); auto arr2 = ::_mm_loadu_si128(
reinterpret_cast<const __m128i*>(needles.data()));
// do an unaligned load for first block of haystack // do an unaligned load for first block of haystack
auto arr1 = __builtin_ia32_loaddqu(haystack.data()); auto arr1 = ::_mm_loadu_si128(
auto index = __builtin_ia32_pcmpestri128(arr2, needles.size(), reinterpret_cast<const __m128i*>(haystack.data()));
arr1, haystack.size(), 0); auto index = __builtin_ia32_pcmpestri128((__v16qi)arr2, needles.size(),
(__v16qi)arr1, haystack.size(), 0);
if (index < 16) { if (index < 16) {
return index; return index;
} }
...@@ -82,58 +80,22 @@ size_t qfind_first_byte_of_needles16(const StringPiece haystack, ...@@ -82,58 +80,22 @@ size_t qfind_first_byte_of_needles16(const StringPiece haystack,
// Now, we can do aligned loads hereafter... // Now, we can do aligned loads hereafter...
size_t i = nextAlignedIndex(haystack.data()); size_t i = nextAlignedIndex(haystack.data());
for (; i < haystack.size(); i+= 16) { for (; i < haystack.size(); i+= 16) {
void* ptr1 = __builtin_assume_aligned(haystack.data() + i, 16); auto arr1 = ::_mm_load_si128(
auto arr1 = *reinterpret_cast<const __v16qi*>(ptr1); reinterpret_cast<const __m128i*>(haystack.data() + i));
auto index = __builtin_ia32_pcmpestri128(arr2, needles.size(), auto index = __builtin_ia32_pcmpestri128(
arr1, haystack.size() - i, 0); (__v16qi)arr2, needles.size(),
(__v16qi)arr1, haystack.size() - i, 0);
if (index < 16) { if (index < 16) {
return i + index; return i + index;
} }
} }
return StringPiece::npos; return std::string::npos;
}
#endif // FOLLY_HAVE_EMMINTRIN_H && GCC 4.6+
} // namespace
namespace detail {
size_t qfind_first_byte_of_byteset(const StringPiece haystack,
const StringPiece needles) {
SparseByteSet s;
for (auto needle: needles) {
s.add(needle);
}
for (size_t index = 0; index < haystack.size(); ++index) {
if (s.contains(haystack[index])) {
return index;
}
}
return StringPiece::npos;
} }
size_t qfind_first_byte_of_bitset(const StringPiece haystack,
const StringPiece needles) {
std::bitset<256> s;
for (auto needle : needles) {
s[(uint8_t)needle] = true;
}
for (size_t index = 0; index < haystack.size(); ++index) {
if (s[(uint8_t)haystack[index]]) {
return index;
}
}
return StringPiece::npos;
}
#if FOLLY_HAVE_EMMINTRIN_H && __GNUC_PREREQ(4, 6)
template <bool HAYSTACK_ALIGNED> template <bool HAYSTACK_ALIGNED>
size_t scanHaystackBlock(const StringPiece haystack, size_t scanHaystackBlock(const StringPieceLite haystack,
const StringPiece needles, const StringPieceLite needles,
uint64_t idx) uint64_t idx)
// inline is okay because it's only called from other sse4.2 functions
__attribute__ ((__target__("sse4.2")))
// Turn off ASAN because the "arr2 = ..." assignment in the loop below reads // Turn off ASAN because the "arr2 = ..." assignment in the loop below reads
// up to 15 bytes beyond end of the buffer in #needles#. That is ok because // up to 15 bytes beyond end of the buffer in #needles#. That is ok because
// ptr2 is always 16-byte aligned, so the read can never span a page boundary. // ptr2 is always 16-byte aligned, so the read can never span a page boundary.
...@@ -145,51 +107,53 @@ size_t scanHaystackBlock(const StringPiece haystack, ...@@ -145,51 +107,53 @@ size_t scanHaystackBlock(const StringPiece haystack,
// If !HAYSTACK_ALIGNED, then caller must ensure that it is safe to load the // If !HAYSTACK_ALIGNED, then caller must ensure that it is safe to load the
// block. // block.
template <bool HAYSTACK_ALIGNED> template <bool HAYSTACK_ALIGNED>
size_t scanHaystackBlock(const StringPiece haystack, size_t scanHaystackBlock(const StringPieceLite haystack,
const StringPiece needles, const StringPieceLite needles,
uint64_t blockStartIdx) { uint64_t blockStartIdx) {
DCHECK_GT(needles.size(), 16); // should handled by *needles16() method DCHECK_GT(needles.size(), 16); // should handled by *needles16() method
DCHECK(blockStartIdx + 16 <= haystack.size() || DCHECK(blockStartIdx + 16 <= haystack.size() ||
(PAGE_FOR(haystack.data() + blockStartIdx) == (page_for(haystack.data() + blockStartIdx) ==
PAGE_FOR(haystack.data() + blockStartIdx + 15))); page_for(haystack.data() + blockStartIdx + 15)));
__v16qi arr1; __m128i arr1;
if (HAYSTACK_ALIGNED) { if (HAYSTACK_ALIGNED) {
void* ptr1 = __builtin_assume_aligned(haystack.data() + blockStartIdx, 16); arr1 = ::_mm_load_si128(
arr1 = *reinterpret_cast<const __v16qi*>(ptr1); reinterpret_cast<const __m128i*>(haystack.data() + blockStartIdx));
} else { } else {
arr1 = __builtin_ia32_loaddqu(haystack.data() + blockStartIdx); arr1 = ::_mm_loadu_si128(
reinterpret_cast<const __m128i*>(haystack.data() + blockStartIdx));
} }
// This load is safe because needles.size() >= 16 // This load is safe because needles.size() >= 16
auto arr2 = __builtin_ia32_loaddqu(needles.data()); auto arr2 = ::_mm_loadu_si128(
reinterpret_cast<const __m128i*>(needles.data()));
size_t b = __builtin_ia32_pcmpestri128( size_t b = __builtin_ia32_pcmpestri128(
arr2, 16, arr1, haystack.size() - blockStartIdx, 0); (__v16qi)arr2, 16, (__v16qi)arr1, haystack.size() - blockStartIdx, 0);
size_t j = nextAlignedIndex(needles.data()); size_t j = nextAlignedIndex(needles.data());
for (; j < needles.size(); j += 16) { for (; j < needles.size(); j += 16) {
void* ptr2 = __builtin_assume_aligned(needles.data() + j, 16); arr2 = ::_mm_load_si128(
arr2 = *reinterpret_cast<const __v16qi*>(ptr2); reinterpret_cast<const __m128i*>(needles.data() + j));
auto index = __builtin_ia32_pcmpestri128( auto index = __builtin_ia32_pcmpestri128(
arr2, needles.size() - j, arr1, haystack.size() - blockStartIdx, 0); (__v16qi)arr2, needles.size() - j,
(__v16qi)arr1, haystack.size() - blockStartIdx, 0);
b = std::min<size_t>(index, b); b = std::min<size_t>(index, b);
} }
if (b < 16) { if (b < 16) {
return blockStartIdx + b; return blockStartIdx + b;
} }
return StringPiece::npos; return std::string::npos;
} }
size_t qfind_first_byte_of_sse42(const StringPiece haystack, size_t qfind_first_byte_of_sse42(const StringPieceLite haystack,
const StringPiece needles) const StringPieceLite needles);
__attribute__ ((__target__("sse4.2"), noinline));
size_t qfind_first_byte_of_sse42(const StringPiece haystack, size_t qfind_first_byte_of_sse42(const StringPieceLite haystack,
const StringPiece needles) { const StringPieceLite needles) {
if (UNLIKELY(needles.empty() || haystack.empty())) { if (UNLIKELY(needles.empty() || haystack.empty())) {
return StringPiece::npos; return std::string::npos;
} else if (needles.size() <= 16) { } else if (needles.size() <= 16) {
// we can save some unnecessary load instructions by optimizing for // we can save some unnecessary load instructions by optimizing for
// the common case of needles.size() <= 16 // the common case of needles.size() <= 16
...@@ -197,46 +161,30 @@ size_t qfind_first_byte_of_sse42(const StringPiece haystack, ...@@ -197,46 +161,30 @@ size_t qfind_first_byte_of_sse42(const StringPiece haystack,
} }
if (haystack.size() < 16 && if (haystack.size() < 16 &&
PAGE_FOR(haystack.end() - 1) != PAGE_FOR(haystack.data() + 16)) { page_for(haystack.end() - 1) != page_for(haystack.data() + 16)) {
// We can't safely SSE-load haystack. Use a different approach. // We can't safely SSE-load haystack. Use a different approach.
if (haystack.size() <= 2) { if (haystack.size() <= 2) {
return qfind_first_of(haystack, needles, AsciiCaseSensitive()); return qfind_first_byte_of_std(haystack, needles);
} }
return qfind_first_byte_of_byteset(haystack, needles); return qfind_first_byte_of_byteset(haystack, needles);
} }
auto ret = scanHaystackBlock<false>(haystack, needles, 0); auto ret = scanHaystackBlock<false>(haystack, needles, 0);
if (ret != StringPiece::npos) { if (ret != std::string::npos) {
return ret; return ret;
} }
size_t i = nextAlignedIndex(haystack.data()); size_t i = nextAlignedIndex(haystack.data());
for (; i < haystack.size(); i += 16) { for (; i < haystack.size(); i += 16) {
auto ret = scanHaystackBlock<true>(haystack, needles, i); auto ret = scanHaystackBlock<true>(haystack, needles, i);
if (ret != StringPiece::npos) { if (ret != std::string::npos) {
return ret; return ret;
} }
} }
return StringPiece::npos; return std::string::npos;
} }
#endif // FOLLY_HAVE_EMMINTRIN_H && GCC 4.6+
size_t qfind_first_byte_of_nosse(const StringPiece haystack,
const StringPiece needles) {
if (UNLIKELY(needles.empty() || haystack.empty())) {
return StringPiece::npos;
}
// The thresholds below were empirically determined by benchmarking.
// This is not an exact science since it depends on the CPU, the size of
// needles, and the size of haystack.
if ((needles.size() >= 4 && haystack.size() <= 10) ||
(needles.size() >= 16 && haystack.size() <= 64) ||
needles.size() >= 32) {
return qfind_first_byte_of_byteset(haystack, needles);
}
return qfind_first_of(haystack, needles, AsciiCaseSensitive());
} }
} // namespace detail }
} // namespace folly
/*
* Copyright 2015 Facebook, Inc.
*
* 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.
*/
#ifndef FOLLY_DETAIL_RANGE_SSE42_H_
#define FOLLY_DETAIL_RANGE_SSE42_H_
#include <cstddef>
#include <folly/detail/RangeCommon.h>
namespace folly {
namespace detail {
size_t qfind_first_byte_of_sse42(const StringPieceLite haystack,
const StringPieceLite needles);
}
}
#endif
...@@ -22,18 +22,6 @@ ...@@ -22,18 +22,6 @@
#include <random> #include <random>
#include <string> #include <string>
namespace folly { namespace detail {
// declaration of functions in Range.cpp
size_t qfind_first_byte_of_byteset(const StringPiece haystack,
const StringPiece needles);
size_t qfind_first_byte_of_bitset(const StringPiece haystack,
const StringPiece needles);
size_t qfind_first_byte_of_nosse(const StringPiece haystack,
const StringPiece needles);
}}
using namespace folly; using namespace folly;
using namespace std; using namespace std;
...@@ -147,12 +135,6 @@ BENCHMARK_RELATIVE(FindSingleCharRange, n) { ...@@ -147,12 +135,6 @@ BENCHMARK_RELATIVE(FindSingleCharRange, n) {
BENCHMARK_DRAW_LINE(); BENCHMARK_DRAW_LINE();
// it's useful to compare our custom implementations vs. the standard library
inline size_t qfind_first_byte_of_std(const StringPiece haystack,
const StringPiece needles) {
return qfind_first_of(haystack, needles, AsciiCaseSensitive());
}
template <class Func> template <class Func>
void countHits(Func func, size_t n) { void countHits(Func func, size_t n) {
StringPiece needles = "\r\n\1"; StringPiece needles = "\r\n\1";
...@@ -188,7 +170,7 @@ BENCHMARK_RELATIVE(FindFirstOf1NeedlesNoSSE, n) { ...@@ -188,7 +170,7 @@ BENCHMARK_RELATIVE(FindFirstOf1NeedlesNoSSE, n) {
} }
BENCHMARK_RELATIVE(FindFirstOf1NeedlesStd, n) { BENCHMARK_RELATIVE(FindFirstOf1NeedlesStd, n) {
findFirstOfRange(delims1, qfind_first_byte_of_std, n); findFirstOfRange(delims1, detail::qfind_first_byte_of_std, n);
} }
BENCHMARK_RELATIVE(FindFirstOf1NeedlesByteSet, n) { BENCHMARK_RELATIVE(FindFirstOf1NeedlesByteSet, n) {
...@@ -212,7 +194,7 @@ BENCHMARK_RELATIVE(FindFirstOf2NeedlesNoSSE, n) { ...@@ -212,7 +194,7 @@ BENCHMARK_RELATIVE(FindFirstOf2NeedlesNoSSE, n) {
} }
BENCHMARK_RELATIVE(FindFirstOf2NeedlesStd, n) { BENCHMARK_RELATIVE(FindFirstOf2NeedlesStd, n) {
findFirstOfRange(delims2, qfind_first_byte_of_std, n); findFirstOfRange(delims2, detail::qfind_first_byte_of_std, n);
} }
BENCHMARK_RELATIVE(FindFirstOf2NeedlesByteSet, n) { BENCHMARK_RELATIVE(FindFirstOf2NeedlesByteSet, n) {
...@@ -236,7 +218,7 @@ BENCHMARK_RELATIVE(FindFirstOf4NeedlesNoSSE, n) { ...@@ -236,7 +218,7 @@ BENCHMARK_RELATIVE(FindFirstOf4NeedlesNoSSE, n) {
} }
BENCHMARK_RELATIVE(FindFirstOf4NeedlesStd, n) { BENCHMARK_RELATIVE(FindFirstOf4NeedlesStd, n) {
findFirstOfRange(delims4, qfind_first_byte_of_std, n); findFirstOfRange(delims4, detail::qfind_first_byte_of_std, n);
} }
BENCHMARK_RELATIVE(FindFirstOf4NeedlesByteSet, n) { BENCHMARK_RELATIVE(FindFirstOf4NeedlesByteSet, n) {
...@@ -260,7 +242,7 @@ BENCHMARK_RELATIVE(FindFirstOf8NeedlesNoSSE, n) { ...@@ -260,7 +242,7 @@ BENCHMARK_RELATIVE(FindFirstOf8NeedlesNoSSE, n) {
} }
BENCHMARK_RELATIVE(FindFirstOf8NeedlesStd, n) { BENCHMARK_RELATIVE(FindFirstOf8NeedlesStd, n) {
findFirstOfRange(delims8, qfind_first_byte_of_std, n); findFirstOfRange(delims8, detail::qfind_first_byte_of_std, n);
} }
BENCHMARK_RELATIVE(FindFirstOf8NeedlesByteSet, n) { BENCHMARK_RELATIVE(FindFirstOf8NeedlesByteSet, n) {
...@@ -284,7 +266,7 @@ BENCHMARK_RELATIVE(FindFirstOf16NeedlesNoSSE, n) { ...@@ -284,7 +266,7 @@ BENCHMARK_RELATIVE(FindFirstOf16NeedlesNoSSE, n) {
} }
BENCHMARK_RELATIVE(FindFirstOf16NeedlesStd, n) { BENCHMARK_RELATIVE(FindFirstOf16NeedlesStd, n) {
findFirstOfRange(delims16, qfind_first_byte_of_std, n); findFirstOfRange(delims16, detail::qfind_first_byte_of_std, n);
} }
BENCHMARK_RELATIVE(FindFirstOf16NeedlesByteSet, n) { BENCHMARK_RELATIVE(FindFirstOf16NeedlesByteSet, n) {
...@@ -308,7 +290,7 @@ BENCHMARK_RELATIVE(FindFirstOf32NeedlesNoSSE, n) { ...@@ -308,7 +290,7 @@ BENCHMARK_RELATIVE(FindFirstOf32NeedlesNoSSE, n) {
} }
BENCHMARK_RELATIVE(FindFirstOf32NeedlesStd, n) { BENCHMARK_RELATIVE(FindFirstOf32NeedlesStd, n) {
findFirstOfRange(delims32, qfind_first_byte_of_std, n); findFirstOfRange(delims32, detail::qfind_first_byte_of_std, n);
} }
BENCHMARK_RELATIVE(FindFirstOf32NeedlesByteSet, n) { BENCHMARK_RELATIVE(FindFirstOf32NeedlesByteSet, n) {
...@@ -333,7 +315,7 @@ BENCHMARK_RELATIVE(FindFirstOf64NeedlesNoSSE, n) { ...@@ -333,7 +315,7 @@ BENCHMARK_RELATIVE(FindFirstOf64NeedlesNoSSE, n) {
} }
BENCHMARK_RELATIVE(FindFirstOf64NeedlesStd, n) { BENCHMARK_RELATIVE(FindFirstOf64NeedlesStd, n) {
findFirstOfRange(delims64, qfind_first_byte_of_std, n); findFirstOfRange(delims64, detail::qfind_first_byte_of_std, n);
} }
BENCHMARK_RELATIVE(FindFirstOf64NeedlesByteSet, n) { BENCHMARK_RELATIVE(FindFirstOf64NeedlesByteSet, n) {
...@@ -364,7 +346,7 @@ BENCHMARK_RELATIVE(FindFirstOfRandomNoSSE, n) { ...@@ -364,7 +346,7 @@ BENCHMARK_RELATIVE(FindFirstOfRandomNoSSE, n) {
} }
BENCHMARK_RELATIVE(FindFirstOfRandomStd, n) { BENCHMARK_RELATIVE(FindFirstOfRandomStd, n) {
findFirstOfRandom(qfind_first_byte_of_std, n); findFirstOfRandom(detail::qfind_first_byte_of_std, n);
} }
BENCHMARK_RELATIVE(FindFirstOfRandomByteSet, n) { BENCHMARK_RELATIVE(FindFirstOfRandomByteSet, n) {
...@@ -386,7 +368,7 @@ BENCHMARK_RELATIVE(CountDelimsNoSSE, n) { ...@@ -386,7 +368,7 @@ BENCHMARK_RELATIVE(CountDelimsNoSSE, n) {
} }
BENCHMARK_RELATIVE(CountDelimsStd, n) { BENCHMARK_RELATIVE(CountDelimsStd, n) {
countHits(qfind_first_byte_of_std, n); countHits(detail::qfind_first_byte_of_std, n);
} }
BENCHMARK_RELATIVE(CountDelimsByteSet, n) { BENCHMARK_RELATIVE(CountDelimsByteSet, n) {
......
...@@ -31,14 +31,6 @@ ...@@ -31,14 +31,6 @@
#include <boost/range/concepts.hpp> #include <boost/range/concepts.hpp>
#include <gtest/gtest.h> #include <gtest/gtest.h>
namespace folly { namespace detail {
// declaration of functions in Range.cpp
size_t qfind_first_byte_of_byteset(const StringPiece haystack,
const StringPiece needles);
}} // namespaces
using namespace folly; using namespace folly;
using namespace std; using namespace std;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment