Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
R
rapidjson
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
rapidjson
Commits
69d0f41c
Commit
69d0f41c
authored
Jan 22, 2016
by
Milo Yip
Browse files
Options
Browse Files
Download
Plain Diff
Implemented ScanCopyUnescapeString optimization
Some performance issues to be fixed
parents
df76c0d6
8fbe4429
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
104 additions
and
8 deletions
+104
-8
reader.h
include/rapidjson/reader.h
+73
-7
rapidjsontest.cpp
test/perftest/rapidjsontest.cpp
+23
-1
readertest.cpp
test/unittest/readertest.cpp
+8
-0
No files found.
include/rapidjson/reader.h
View file @
69d0f41c
...
@@ -679,7 +679,14 @@ private:
...
@@ -679,7 +679,14 @@ private:
*
stack_
.
template
Push
<
Ch
>
()
=
c
;
*
stack_
.
template
Push
<
Ch
>
()
=
c
;
++
length_
;
++
length_
;
}
}
RAPIDJSON_FORCEINLINE
void
*
Push
(
size_t
count
)
{
length_
+=
count
;
return
stack_
.
template
Push
<
Ch
>
(
count
);
}
size_t
Length
()
const
{
return
length_
;
}
size_t
Length
()
const
{
return
length_
;
}
Ch
*
Pop
()
{
Ch
*
Pop
()
{
return
stack_
.
template
Pop
<
Ch
>
(
length_
);
return
stack_
.
template
Pop
<
Ch
>
(
length_
);
}
}
...
@@ -740,6 +747,10 @@ private:
...
@@ -740,6 +747,10 @@ private:
is
.
Take
();
// Skip '\"'
is
.
Take
();
// Skip '\"'
for
(;;)
{
for
(;;)
{
// Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation.
if
(
!
(
parseFlags
&
kParseValidateEncodingFlag
))
ScanCopyUnescapedString
(
is
,
os
);
Ch
c
=
is
.
Peek
();
Ch
c
=
is
.
Peek
();
if
(
RAPIDJSON_UNLIKELY
(
c
==
'\\'
))
{
// Escape
if
(
RAPIDJSON_UNLIKELY
(
c
==
'\\'
))
{
// Escape
is
.
Take
();
is
.
Take
();
...
@@ -769,10 +780,12 @@ private:
...
@@ -769,10 +780,12 @@ private:
os
.
Put
(
'\0'
);
// null-terminate the string
os
.
Put
(
'\0'
);
// null-terminate the string
return
;
return
;
}
}
else
if
(
RAPIDJSON_UNLIKELY
(
c
==
'\0'
))
else
if
(
RAPIDJSON_UNLIKELY
(
static_cast
<
unsigned
>
(
c
)
<
0x20
))
{
// RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
RAPIDJSON_PARSE_ERROR
(
kParseErrorStringMissQuotationMark
,
is
.
Tell
()
-
1
);
if
(
c
==
'\0'
)
else
if
(
RAPIDJSON_UNLIKELY
(
static_cast
<
unsigned
>
(
c
)
<
0x20
))
// RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
RAPIDJSON_PARSE_ERROR
(
kParseErrorStringMissQuotationMark
,
is
.
Tell
()
-
1
);
RAPIDJSON_PARSE_ERROR
(
kParseErrorStringEscapeInvalid
,
is
.
Tell
()
-
1
);
else
RAPIDJSON_PARSE_ERROR
(
kParseErrorStringEscapeInvalid
,
is
.
Tell
()
-
1
);
}
else
{
else
{
if
(
RAPIDJSON_UNLIKELY
((
parseFlags
&
kParseValidateEncodingFlag
?
if
(
RAPIDJSON_UNLIKELY
((
parseFlags
&
kParseValidateEncodingFlag
?
!
Transcoder
<
SEncoding
,
TEncoding
>::
Validate
(
is
,
os
)
:
!
Transcoder
<
SEncoding
,
TEncoding
>::
Validate
(
is
,
os
)
:
...
@@ -782,6 +795,59 @@ private:
...
@@ -782,6 +795,59 @@ private:
}
}
}
}
template
<
typename
InputStream
,
typename
OutputStream
>
static
RAPIDJSON_FORCEINLINE
void
ScanCopyUnescapedString
(
InputStream
&
,
OutputStream
&
)
{
// Do nothing for generic version
}
#if 0 //defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream<char>& os) {
const char* p = is.src_;
// Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
while (p != nextAligned)
if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(*p < 0x20)) {
is.src_ = p;
return;
}
else
os.Put(*p++);
// The rest of string using SIMD
static const char dquote[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 };
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 sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
for (;; p += 16) {
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
__m128i x = _mm_cmpeq_epi8(s, dq);
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, bs));
x = _mm_or_si128(x, _mm_cmplt_epi8(s, sp));
unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
size_t length;
#ifdef _MSC_VER // Find the index of first escaped
unsigned long offset;
_BitScanForward(&offset, r);
length = offset;
#else
length = static_cast<size_t>(__builtin_ffs(r) - 1);
#endif
memcpy
(
os
.
Push
(
length
),
p
,
length
);
p
+=
length
;
break
;
}
_mm_storeu_si128
(
reinterpret_cast
<
__m128i
*>
(
os
.
Push
(
16
)),
s
);
}
is
.
src_
=
p
;
}
#endif
template
<
typename
InputStream
,
bool
backup
>
template
<
typename
InputStream
,
bool
backup
>
class
NumberStream
;
class
NumberStream
;
...
@@ -887,7 +953,7 @@ private:
...
@@ -887,7 +953,7 @@ private:
while
(
RAPIDJSON_LIKELY
(
s
.
Peek
()
>=
'0'
&&
s
.
Peek
()
<=
'9'
))
{
while
(
RAPIDJSON_LIKELY
(
s
.
Peek
()
>=
'0'
&&
s
.
Peek
()
<=
'9'
))
{
if
(
RAPIDJSON_UNLIKELY
(
i64
>=
RAPIDJSON_UINT64_C2
(
0x0CCCCCCC
,
0xCCCCCCCC
)))
// 2^63 = 9223372036854775808
if
(
RAPIDJSON_UNLIKELY
(
i64
>=
RAPIDJSON_UINT64_C2
(
0x0CCCCCCC
,
0xCCCCCCCC
)))
// 2^63 = 9223372036854775808
if
(
RAPIDJSON_LIKELY
(
i64
!=
RAPIDJSON_UINT64_C2
(
0x0CCCCCCC
,
0xCCCCCCCC
)
||
s
.
Peek
()
>
'8'
))
{
if
(
RAPIDJSON_LIKELY
(
i64
!=
RAPIDJSON_UINT64_C2
(
0x0CCCCCCC
,
0xCCCCCCCC
)
||
s
.
Peek
()
>
'8'
))
{
d
=
i64
;
d
=
static_cast
<
double
>
(
i64
)
;
useDouble
=
true
;
useDouble
=
true
;
break
;
break
;
}
}
...
@@ -898,7 +964,7 @@ private:
...
@@ -898,7 +964,7 @@ private:
while
(
RAPIDJSON_LIKELY
(
s
.
Peek
()
>=
'0'
&&
s
.
Peek
()
<=
'9'
))
{
while
(
RAPIDJSON_LIKELY
(
s
.
Peek
()
>=
'0'
&&
s
.
Peek
()
<=
'9'
))
{
if
(
RAPIDJSON_UNLIKELY
(
i64
>=
RAPIDJSON_UINT64_C2
(
0x19999999
,
0x99999999
)))
// 2^64 - 1 = 18446744073709551615
if
(
RAPIDJSON_UNLIKELY
(
i64
>=
RAPIDJSON_UINT64_C2
(
0x19999999
,
0x99999999
)))
// 2^64 - 1 = 18446744073709551615
if
(
RAPIDJSON_LIKELY
(
i64
!=
RAPIDJSON_UINT64_C2
(
0x19999999
,
0x99999999
)
||
s
.
Peek
()
>
'5'
))
{
if
(
RAPIDJSON_LIKELY
(
i64
!=
RAPIDJSON_UINT64_C2
(
0x19999999
,
0x99999999
)
||
s
.
Peek
()
>
'5'
))
{
d
=
i64
;
d
=
static_cast
<
double
>
(
i64
)
;
useDouble
=
true
;
useDouble
=
true
;
break
;
break
;
}
}
...
@@ -969,7 +1035,7 @@ private:
...
@@ -969,7 +1035,7 @@ private:
int
exp
=
0
;
int
exp
=
0
;
if
(
s
.
Peek
()
==
'e'
||
s
.
Peek
()
==
'E'
)
{
if
(
s
.
Peek
()
==
'e'
||
s
.
Peek
()
==
'E'
)
{
if
(
!
useDouble
)
{
if
(
!
useDouble
)
{
d
=
use64bit
?
i64
:
i
;
d
=
static_cast
<
double
>
(
use64bit
?
i64
:
i
)
;
useDouble
=
true
;
useDouble
=
true
;
}
}
s
.
Take
();
s
.
Take
();
...
...
test/perftest/rapidjsontest.cpp
View file @
69d0f41c
...
@@ -95,6 +95,26 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler)) {
...
@@ -95,6 +95,26 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler)) {
}
}
}
}
#define TEST_TYPED(index, Name)\
TEST_F
(
RapidJson
,
SIMD_SUFFIX
(
ReaderParse_DummyHandler_
##
Name
))
{
\
for
(
size_t
i
=
0
;
i
<
kTrialCount
*
10
;
i
++
)
{
\
StringStream
s
(
types_
[
index
]);
\
BaseReaderHandler
<>
h
;
\
Reader
reader
;
\
EXPECT_TRUE
(
reader
.
Parse
(
s
,
h
));
\
}
\
}
TEST_TYPED
(
0
,
Booleans
)
TEST_TYPED
(
1
,
Floats
)
TEST_TYPED
(
2
,
Guids
)
TEST_TYPED
(
3
,
Integers
)
TEST_TYPED
(
4
,
Mixed
)
TEST_TYPED
(
5
,
Nulls
)
TEST_TYPED
(
6
,
Paragraphs
)
#undef TEST_TYPED
TEST_F
(
RapidJson
,
SIMD_SUFFIX
(
ReaderParse_DummyHandler_FullPrecision
))
{
TEST_F
(
RapidJson
,
SIMD_SUFFIX
(
ReaderParse_DummyHandler_FullPrecision
))
{
for
(
size_t
i
=
0
;
i
<
kTrialCount
;
i
++
)
{
for
(
size_t
i
=
0
;
i
<
kTrialCount
;
i
++
)
{
StringStream
s
(
json_
);
StringStream
s
(
json_
);
...
@@ -293,7 +313,7 @@ TEST_F(RapidJson, Writer_StringBuffer_##Name) {\
...
@@ -293,7 +313,7 @@ TEST_F(RapidJson, Writer_StringBuffer_##Name) {\
const
char
*
str
=
s
.
GetString
();
\
const
char
*
str
=
s
.
GetString
();
\
(
void
)
str
;
\
(
void
)
str
;
\
}
\
}
\
}
\
}
TEST_TYPED
(
0
,
Booleans
)
TEST_TYPED
(
0
,
Booleans
)
TEST_TYPED
(
1
,
Floats
)
TEST_TYPED
(
1
,
Floats
)
...
@@ -303,6 +323,8 @@ TEST_TYPED(4, Mixed)
...
@@ -303,6 +323,8 @@ TEST_TYPED(4, Mixed)
TEST_TYPED
(
5
,
Nulls
)
TEST_TYPED
(
5
,
Nulls
)
TEST_TYPED
(
6
,
Paragraphs
)
TEST_TYPED
(
6
,
Paragraphs
)
#undef TEST_TYPED
TEST_F
(
RapidJson
,
PrettyWriter_StringBuffer
)
{
TEST_F
(
RapidJson
,
PrettyWriter_StringBuffer
)
{
for
(
size_t
i
=
0
;
i
<
kTrialCount
;
i
++
)
{
for
(
size_t
i
=
0
;
i
<
kTrialCount
;
i
++
)
{
StringBuffer
s
(
0
,
2048
*
1024
);
StringBuffer
s
(
0
,
2048
*
1024
);
...
...
test/unittest/readertest.cpp
View file @
69d0f41c
...
@@ -14,6 +14,14 @@
...
@@ -14,6 +14,14 @@
#include "unittest.h"
#include "unittest.h"
// __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler.
// We use -march=native with gmake to enable -msse2 and -msse4.2, if supported.
#if defined(__SSE4_2__)
# define RAPIDJSON_SSE42
#elif defined(__SSE2__)
# define RAPIDJSON_SSE2
#endif
#include "rapidjson/reader.h"
#include "rapidjson/reader.h"
#include "rapidjson/internal/dtoa.h"
#include "rapidjson/internal/dtoa.h"
#include "rapidjson/internal/itoa.h"
#include "rapidjson/internal/itoa.h"
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment