Commit ae5cf588 authored by Milo Yip's avatar Milo Yip

Fix ScanCopyUnescapedString performance issue

parent 1502e7ed
...@@ -178,9 +178,9 @@ ...@@ -178,9 +178,9 @@
#ifndef RAPIDJSON_FORCEINLINE #ifndef RAPIDJSON_FORCEINLINE
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#if defined(_MSC_VER) && !defined(NDEBUG) #if defined(_MSC_VER) && defined(NDEBUG)
#define RAPIDJSON_FORCEINLINE __forceinline #define RAPIDJSON_FORCEINLINE __forceinline
#elif defined(__GNUC__) && __GNUC__ >= 4 && !defined(NDEBUG) #elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG)
#define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) #define RAPIDJSON_FORCEINLINE __attribute__((always_inline))
#else #else
#define RAPIDJSON_FORCEINLINE #define RAPIDJSON_FORCEINLINE
......
...@@ -800,11 +800,12 @@ private: ...@@ -800,11 +800,12 @@ private:
// Do nothing for generic version // Do nothing for generic version
} }
#if 0 //defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream<char>& os) { static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream<char>& os) {
const char* p = is.src_; const char* p = is.src_;
// Scan one by one until alignment (unaligned load may cross page boundary and cause crash) // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
const char* start = p;
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15)); const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
while (p != nextAligned) while (p != nextAligned)
if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(*p < 0x20)) { if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(*p < 0x20)) {
...@@ -817,16 +818,17 @@ private: ...@@ -817,16 +818,17 @@ private:
// The rest of string using SIMD // The rest of string using SIMD
static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
static const char space[16] = { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0])); const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
for (;; p += 16) { for (;; p += 16) {
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p)); const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
__m128i x = _mm_cmpeq_epi8(s, dq); const __m128i t1 = _mm_cmpeq_epi8(s, dq);
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, bs)); const __m128i t2 = _mm_cmpeq_epi8(s, bs);
x = _mm_or_si128(x, _mm_cmplt_epi8(s, sp)); const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x)); unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
size_t length; size_t length;
...@@ -837,7 +839,10 @@ private: ...@@ -837,7 +839,10 @@ private:
#else #else
length = static_cast<size_t>(__builtin_ffs(r) - 1); length = static_cast<size_t>(__builtin_ffs(r) - 1);
#endif #endif
memcpy(os.Push(length), p, length); char* q = reinterpret_cast<char*>(os.Push(length));
for (size_t i = 0; i < length; i++)
q[i] = p[i];
p += length; p += length;
break; break;
} }
......
...@@ -24,14 +24,6 @@ ...@@ -24,14 +24,6 @@
#include "rapidjson/encodedstream.h" #include "rapidjson/encodedstream.h"
#include "rapidjson/memorystream.h" #include "rapidjson/memorystream.h"
#ifdef RAPIDJSON_SSE2
#define SIMD_SUFFIX(name) name##_SSE2
#elif defined(RAPIDJSON_SSE42)
#define SIMD_SUFFIX(name) name##_SSE42
#else
#define SIMD_SUFFIX(name) name
#endif
using namespace rapidjson; using namespace rapidjson;
class RapidJson : public PerfTest { class RapidJson : public PerfTest {
......
...@@ -66,3 +66,30 @@ TEST(SIMD, SIMD_SUFFIX(SkipWhitespace)) { ...@@ -66,3 +66,30 @@ TEST(SIMD, SIMD_SUFFIX(SkipWhitespace)) {
TestSkipWhitespace<StringStream>(); TestSkipWhitespace<StringStream>();
TestSkipWhitespace<InsituStringStream>(); TestSkipWhitespace<InsituStringStream>();
} }
template <typename Encoding>
struct ParseStringHandler : BaseReaderHandler<Encoding, ParseStringHandler<Encoding> > {
ParseStringHandler() : str_(0), length_(0), copy_() {}
~ParseStringHandler() { EXPECT_TRUE(str_ != 0); if (copy_) free(const_cast<typename Encoding::Ch*>(str_)); }
ParseStringHandler(const ParseStringHandler&);
ParseStringHandler& operator=(const ParseStringHandler&);
bool Default() { ADD_FAILURE(); return false; }
bool String(const typename Encoding::Ch* str, size_t length, bool copy) {
EXPECT_EQ(0, str_);
if (copy) {
str_ = static_cast<typename Encoding::Ch*>(malloc((length + 1) * sizeof(typename Encoding::Ch)));
memcpy(const_cast<typename Encoding::Ch*>(str_), str, (length + 1) * sizeof(typename Encoding::Ch));
}
else
str_ = str;
length_ = length;
copy_ = copy;
return true;
}
const typename Encoding::Ch* str_;
size_t length_;
bool copy_;
};
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