Skip to content

Commit

Permalink
improved deserialize performance
Browse files Browse the repository at this point in the history
  • Loading branch information
wenshao committed Jul 23, 2022
1 parent 97c2313 commit 296798f
Show file tree
Hide file tree
Showing 12 changed files with 841 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ public static void main(String[] args) throws RunnerException {
.exclude(EishayParseTreeUTF8BytesPretty.class.getName())
.mode(Mode.Throughput)
.timeUnit(TimeUnit.MILLISECONDS)
.warmupIterations(3)
.forks(1)
.build();
new Runner(options).run();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.alibaba.fastjson2.benchmark.eishay;

import org.openjdk.jmh.infra.Blackhole;

public class EishayParseTreeStringTest {
static final Blackhole BH = new Blackhole("Today's password is swordfish. I understand instantiating Blackholes directly is dangerous.");

public static void fastjson2_perf_test() {
for (int i = 0; i < 10; i++) {
fastjson2_perf();
}
}

public static void fastjson2_perf() {
EishayParseTreeString perf = new EishayParseTreeString();
long start = System.currentTimeMillis();
for (int i = 0; i < 1000 * 1000; ++i) {
perf.fastjson2(BH);
}
long millis = System.currentTimeMillis() - start;
System.out.println("fastjson2 millis : " + millis);
// zulu17.32.13 :
// zulu11.52.13 :
// zulu8.58.0.13 : 725
}

public static void jackson_perf_test() throws Exception {
for (int i = 0; i < 10; i++) {
jackson_perf();
}
}

public static void jackson_perf() throws Exception {
EishayParseTreeString perf = new EishayParseTreeString();
long start = System.currentTimeMillis();
for (int i = 0; i < 1000 * 1000; ++i) {
perf.jackson(BH);
}
long millis = System.currentTimeMillis() - start;
System.out.println("jackson millis : " + millis);
// zulu17.32.13 :
// zulu11.52.13 :
// zulu8.58.0.13 :
}

public static void main(String[] args) throws Exception {
fastjson2_perf_test();
jackson_perf_test();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.alibaba.fastjson2.benchmark.eishay;

import org.openjdk.jmh.infra.Blackhole;

public class EishayParseTreeUTF8BytesTest {
static final Blackhole BH = new Blackhole("Today's password is swordfish. I understand instantiating Blackholes directly is dangerous.");

public static void fastjson2_perf_test() {
for (int i = 0; i < 10; i++) {
fastjson2_perf();
}
}

public static void fastjson2_perf() {
EishayParseTreeUTF8Bytes perf = new EishayParseTreeUTF8Bytes();
long start = System.currentTimeMillis();
for (int i = 0; i < 1000 * 1000; ++i) {
perf.fastjson2(BH);
}
long millis = System.currentTimeMillis() - start;
System.out.println("fastjson2 millis : " + millis);
// zulu17.32.13 :
// zulu11.52.13 :
// zulu8.58.0.13 : 995
}

public static void jackson_perf_test() throws Exception {
for (int i = 0; i < 10; i++) {
jackson_perf();
}
}

public static void jackson_perf() throws Exception {
EishayParseTreeUTF8Bytes perf = new EishayParseTreeUTF8Bytes();
long start = System.currentTimeMillis();
for (int i = 0; i < 1000 * 1000; ++i) {
perf.jackson(BH);
}
long millis = System.currentTimeMillis() - start;
System.out.println("jackson millis : " + millis);
// zulu17.32.13 :
// zulu11.52.13 :
// zulu8.58.0.13 :
}

public static void main(String[] args) throws Exception {
fastjson2_perf_test();
jackson_perf_test();
}
}
11 changes: 11 additions & 0 deletions core/src/main/java/com/alibaba/fastjson2/JSONFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,17 @@ static final class Utils {
static volatile boolean STRING_CREATOR_ERROR;
}

static final NameCacheEntry[] NAME_CACHE = new NameCacheEntry[8192];

static final class NameCacheEntry {
final String name;
final long value;
public NameCacheEntry(String name, long value) {
this.name = name;
this.value = value;
}
}

static final BigDecimal LOW = BigDecimal.valueOf(-9007199254740991L);
static final BigDecimal HIGH = BigDecimal.valueOf(9007199254740991L);
static final BigInteger LOW_BIGINT = BigInteger.valueOf(-9007199254740991L);
Expand Down
95 changes: 95 additions & 0 deletions core/src/main/java/com/alibaba/fastjson2/JSONReaderASCII.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

import static com.alibaba.fastjson2.JSONFactory.NAME_CACHE;
import static com.alibaba.fastjson2.JSONFactory.Utils.*;

final class JSONReaderASCII
Expand Down Expand Up @@ -551,6 +552,100 @@ public String readFieldName() {
offset++;
}

if (!nameEscape) {
long nameValue = -1;
switch (length) {
case 1:
nameValue = bytes[nameBegin];
break;
case 2:
nameValue
= (bytes[nameBegin] << 8)
+ (bytes[nameBegin + 1]);
break;
case 3:
nameValue
= (bytes[nameBegin] << 16)
+ (bytes[nameBegin + 1] << 8)
+ (bytes[nameBegin + 2]);
break;
case 4:
nameValue
= (bytes[nameBegin] << 24)
+ (bytes[nameBegin + 1] << 16)
+ (bytes[nameBegin + 2] << 8)
+ (bytes[nameBegin + 3]);
break;
case 5:
nameValue
= (((long) bytes[nameBegin]) << 32)
+ (((long) bytes[nameBegin + 1]) << 24)
+ (((long) bytes[nameBegin + 2]) << 16)
+ (((long) bytes[nameBegin + 3]) << 8)
+ ((long) bytes[nameBegin + 4]);
break;
case 6:
nameValue
= (((long) bytes[nameBegin]) << 40)
+ (((long) bytes[nameBegin + 1]) << 32)
+ (((long) bytes[nameBegin + 2]) << 24)
+ (((long) bytes[nameBegin + 3]) << 16)
+ (((long) bytes[nameBegin + 4]) << 8)
+ ((long) bytes[nameBegin + 5]);
break;
case 7:
nameValue
= (((long) bytes[nameBegin]) << 48)
+ (((long) bytes[nameBegin + 1]) << 40)
+ (((long) bytes[nameBegin + 2]) << 32)
+ (((long) bytes[nameBegin + 3]) << 24)
+ (((long) bytes[nameBegin + 4]) << 16)
+ (((long) bytes[nameBegin + 5]) << 8)
+ ((long) bytes[nameBegin + 6]);
break;
case 8:
nameValue
= (((long) bytes[nameBegin]) << 56)
+ (((long) bytes[nameBegin + 1]) << 48)
+ (((long) bytes[nameBegin + 2]) << 40)
+ (((long) bytes[nameBegin + 3]) << 32)
+ (((long) bytes[nameBegin + 4]) << 24)
+ (((long) bytes[nameBegin + 5]) << 16)
+ (((long) bytes[nameBegin + 6]) << 8)
+ ((long) bytes[nameBegin + 7]);
break;
}

if (nameValue != -1) {
int indexMask = ((int) nameValue) & (NAME_CACHE.length - 1);
JSONFactory.NameCacheEntry entry = NAME_CACHE[indexMask];
if (entry == null) {
if (STRING_CREATOR_JDK8 == null && !STRING_CREATOR_ERROR) {
try {
STRING_CREATOR_JDK8 = JDKUtils.getStringCreatorJDK8();
} catch (Throwable e) {
STRING_CREATOR_ERROR = true;
}
}
String name;
if (STRING_CREATOR_JDK8 != null) {
char[] chars = new char[length];
for (int i = 0; i < length; ++i) {
chars[i] = (char) bytes[nameBegin + i];
}
name = STRING_CREATOR_JDK8.apply(chars, Boolean.TRUE);
} else {
name = new String(bytes, nameBegin, length, StandardCharsets.US_ASCII);
}

NAME_CACHE[indexMask] = new JSONFactory.NameCacheEntry(name, nameValue);
return name;
} else if (entry.value == nameValue) {
return entry.name;
}
}
}

return getFieldName();
}

Expand Down
105 changes: 99 additions & 6 deletions core/src/main/java/com/alibaba/fastjson2/JSONReaderJSONB.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
import static com.alibaba.fastjson2.JSONB.Constants.*;
import static com.alibaba.fastjson2.JSONB.typeName;
import static com.alibaba.fastjson2.JSONFactory.CACHE_BYTES;
import static com.alibaba.fastjson2.JSONFactory.NAME_CACHE;
import static com.alibaba.fastjson2.JSONFactory.Utils.STRING_CREATOR_ERROR;
import static com.alibaba.fastjson2.JSONFactory.Utils.STRING_CREATOR_JDK8;
import static com.alibaba.fastjson2.util.UUIDUtils.parse4Nibbles;

final class JSONReaderJSONB
Expand Down Expand Up @@ -249,12 +252,7 @@ public Map<String, Object> readObject() {
break;
}

String name;
if (type == BC_SYMBOL) {
name = readFieldName();
} else {
name = readString();
}
String name = readFieldName();

if (isReference()) {
String reference = readReference();
Expand Down Expand Up @@ -1512,11 +1510,106 @@ public String readFieldName() {
Charset charset = null;
String str = null;
if (strtype >= BC_STR_ASCII_FIX_MIN && strtype <= BC_STR_ASCII) {
long nameValue = -1;

if (strtype == BC_STR_ASCII) {
strlen = readLength();
strBegin = offset;
} else {
strlen = strtype - BC_STR_ASCII_FIX_MIN;

switch (strlen) {
case 1:
nameValue = bytes[offset];
break;
case 2:
nameValue
= (bytes[offset] << 8)
+ (bytes[offset + 1]);
break;
case 3:
nameValue
= (bytes[offset] << 16)
+ (bytes[offset + 1] << 8)
+ (bytes[offset + 2]);
break;
case 4:
nameValue
= (bytes[offset] << 24)
+ (bytes[offset + 1] << 16)
+ (bytes[offset + 2] << 8)
+ (bytes[offset + 3]);
break;
case 5:
nameValue
= (((long) bytes[offset]) << 32)
+ (((long) bytes[offset + 1]) << 24)
+ (((long) bytes[offset + 2]) << 16)
+ (((long) bytes[offset + 3]) << 8)
+ ((long) bytes[offset + 4]);
break;
case 6:
nameValue
= (((long) bytes[offset]) << 40)
+ (((long) bytes[offset + 1]) << 32)
+ (((long) bytes[offset + 2]) << 24)
+ (((long) bytes[offset + 3]) << 16)
+ (((long) bytes[offset + 4]) << 8)
+ ((long) bytes[offset + 5]);
break;
case 7:
nameValue
= (((long) bytes[offset]) << 48)
+ (((long) bytes[offset + 1]) << 40)
+ (((long) bytes[offset + 2]) << 32)
+ (((long) bytes[offset + 3]) << 24)
+ (((long) bytes[offset + 4]) << 16)
+ (((long) bytes[offset + 5]) << 8)
+ ((long) bytes[offset + 6]);
break;
case 8:
nameValue
= (((long) bytes[offset]) << 56)
+ (((long) bytes[offset + 1]) << 48)
+ (((long) bytes[offset + 2]) << 40)
+ (((long) bytes[offset + 3]) << 32)
+ (((long) bytes[offset + 4]) << 24)
+ (((long) bytes[offset + 5]) << 16)
+ (((long) bytes[offset + 6]) << 8)
+ ((long) bytes[offset + 7]);
break;
}
}

if (nameValue != -1) {
int indexMask = ((int) nameValue) & (NAME_CACHE.length - 1);
JSONFactory.NameCacheEntry entry = NAME_CACHE[indexMask];
if (entry == null) {
if (STRING_CREATOR_JDK8 == null && !STRING_CREATOR_ERROR) {
try {
STRING_CREATOR_JDK8 = JDKUtils.getStringCreatorJDK8();
} catch (Throwable e) {
STRING_CREATOR_ERROR = true;
}
}
String name;
if (STRING_CREATOR_JDK8 != null) {
char[] chars = new char[strlen];
for (int i = 0; i < strlen; ++i) {
chars[i] = (char) bytes[offset + i];
}
name = STRING_CREATOR_JDK8.apply(chars, Boolean.TRUE);
} else {
name = new String(bytes, offset, strlen, StandardCharsets.US_ASCII);
}

NAME_CACHE[indexMask] = new JSONFactory.NameCacheEntry(name, nameValue);
offset += strlen;
return name;
} else if (entry.value == nameValue) {
offset += strlen;
return entry.name;
}
}

if (JDKUtils.JVM_VERSION == 8 && strlen >= 0) {
Expand Down
Loading

0 comments on commit 296798f

Please sign in to comment.