Skip to content

Commit 0dfc3ea

Browse files
committed
extract out streaming support
1 parent 5d1fa30 commit 0dfc3ea

File tree

13 files changed

+745
-360
lines changed

13 files changed

+745
-360
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package com.jsoniter.demo;
2+
3+
import java.io.File;
4+
import java.lang.management.ManagementFactory;
5+
import java.util.Arrays;
6+
import java.util.Collection;
7+
import java.util.Collections;
8+
import java.util.List;
9+
import org.openjdk.jmh.infra.BenchmarkParams;
10+
import org.openjdk.jmh.profile.ExternalProfiler;
11+
import org.openjdk.jmh.results.AggregationPolicy;
12+
import org.openjdk.jmh.results.Aggregator;
13+
import org.openjdk.jmh.results.BenchmarkResult;
14+
import org.openjdk.jmh.results.Result;
15+
import org.openjdk.jmh.results.ResultRole;
16+
17+
/**
18+
*
19+
* @author zoly
20+
*/
21+
public final class JmhFlightRecorderProfiler implements ExternalProfiler {
22+
23+
private static final String DUMP_FOLDER = System.getProperty("jmh.stack.profiles", "/tmp");
24+
25+
private static final String DEFAULT_OPTIONS = System.getProperty("jmh.fr.options",
26+
"defaultrecording=true,settings=profile");
27+
28+
29+
30+
@Override
31+
public Collection<String> addJVMInvokeOptions(final BenchmarkParams params) {
32+
return Collections.emptyList();
33+
}
34+
35+
private volatile String dumpFile;
36+
37+
private static volatile String benchmarkName;
38+
39+
public static String benchmarkName() {
40+
return benchmarkName;
41+
}
42+
43+
44+
/**
45+
* See:
46+
* http://docs.oracle.com/cd/E15289_01/doc.40/e15070/usingjfr.htm
47+
* and
48+
* http://docs.oracle.com/cd/E15289_01/doc.40/e15070/config_rec_data.htm
49+
* @param params
50+
* @return
51+
*/
52+
@Override
53+
public Collection<String> addJVMOptions(final BenchmarkParams params) {
54+
final String id = params.id();
55+
benchmarkName = id;
56+
dumpFile = DUMP_FOLDER + '/' + id + ".jfr";
57+
String flightRecorderOptions = DEFAULT_OPTIONS + ",dumponexit=true,dumponexitpath=" + dumpFile;
58+
return Arrays.asList(
59+
"-XX:+FlightRecorder",
60+
"-XX:FlightRecorderOptions=" + flightRecorderOptions);
61+
}
62+
63+
@Override
64+
public void beforeTrial(final BenchmarkParams benchmarkParams) {
65+
final List<String> inputArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();
66+
// if (new Version(org.spf4j.base.Runtime.JAVA_VERSION).compareTo(new Version("1.8.0_40")) <= 0
67+
// && !inputArguments.contains("-XX:+UnlockCommercialFeatures")) {
68+
// throw new RuntimeException("-XX:+UnlockCommercialFeatures must pre present in the JVM options,"
69+
// + " current options are: " + inputArguments);
70+
// }
71+
}
72+
73+
74+
@Override
75+
public boolean allowPrintOut() {
76+
return true;
77+
}
78+
79+
@Override
80+
public boolean allowPrintErr() {
81+
return false;
82+
}
83+
84+
85+
@Override
86+
public String getDescription() {
87+
return "Java Flight Recording profiler runs for every benchmark.";
88+
}
89+
90+
@Override
91+
public Collection<? extends Result> afterTrial(final BenchmarkResult bp, final long l,
92+
final File file, final File file1) {
93+
NoResult r = new NoResult("Profile saved to " + dumpFile + ", results: " + bp
94+
+ ", stdOutFile = " + file + ", stdErrFile = " + file1);
95+
return Collections.singleton(r);
96+
}
97+
98+
private static final class NoResult extends Result<NoResult> {
99+
private static final long serialVersionUID = 1L;
100+
101+
private final String output;
102+
103+
NoResult(final String output) {
104+
super(ResultRole.SECONDARY, "JFR", of(Double.NaN), "N/A", AggregationPolicy.SUM);
105+
this.output = output;
106+
}
107+
108+
@Override
109+
protected Aggregator<NoResult> getThreadAggregator() {
110+
return new NoResultAggregator();
111+
}
112+
113+
@Override
114+
protected Aggregator<NoResult> getIterationAggregator() {
115+
return new NoResultAggregator();
116+
}
117+
118+
private static class NoResultAggregator implements Aggregator<NoResult> {
119+
120+
@Override
121+
public NoResult aggregate(final Collection<NoResult> results) {
122+
StringBuilder agg = new StringBuilder();
123+
for (NoResult r : results) {
124+
agg.append(r.output);
125+
}
126+
return new NoResult(agg.toString());
127+
}
128+
}
129+
}
130+
131+
@Override
132+
public String toString() {
133+
return "JmhFlightRecorderProfiler{" + "dumpFile=" + dumpFile + '}';
134+
}
135+
136+
}

demo/src/test/java/com/jsoniter/demo/ModelTest.java

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.openjdk.jmh.annotations.*;
1313
import org.openjdk.jmh.infra.BenchmarkParams;
1414
import org.openjdk.jmh.infra.Blackhole;
15+
import org.openjdk.jmh.runner.RunnerException;
1516

1617
import java.io.IOException;
1718

@@ -31,6 +32,7 @@ public class ModelTest {
3132

3233
@Setup(Level.Trial)
3334
public void benchSetup(BenchmarkParams params) {
35+
JsonIterator.enableStreamingSupport();
3436
input = "{\"name\":\"wenshao\",\"id\":1001}";
3537
inputBytes = input.getBytes();
3638
iter = new JsonIterator();
@@ -43,16 +45,7 @@ public void benchSetup(BenchmarkParams params) {
4345
};
4446
}
4547

46-
@Test
47-
public void test() throws IOException {
48-
benchSetup(null);
49-
iter.reset(inputBytes);
50-
System.out.println(iter.read(modelTypeLiteral).name);
51-
System.out.println(JSON.parseObject(input, Model.class).name);
52-
53-
}
54-
55-
public static void main(String[] args) throws Exception {
48+
public static void main(String[] args) throws IOException, RunnerException {
5649
Main.main(new String[]{
5750
"ModelTest",
5851
"-i", "5",
@@ -61,26 +54,50 @@ public static void main(String[] args) throws Exception {
6154
});
6255
}
6356

57+
@Test
58+
public void test() throws IOException {
59+
benchSetup(null);
60+
iter.reset(inputBytes);
61+
System.out.println(iter.read(modelTypeLiteral).name);
62+
}
63+
64+
// public static void main(String[] args) throws Exception {
65+
// Options opt = new OptionsBuilder()
66+
// .include("ModelTest")
67+
// .addProfiler(JmhFlightRecorderProfiler.class)
68+
// .jvmArgs("-Xmx512m", "-Xms512m", "-XX:+UnlockCommercialFeatures",
69+
// "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintAssembly",
70+
// "-Djmh.stack.profiles=" + "/tmp",
71+
// "-Djmh.executor=FJP",
72+
// "-Djmh.fr.options=defaultrecording=true,settings=profile")
73+
// .warmupIterations(5)
74+
// .measurementTime(TimeValue.seconds(5))
75+
// .measurementIterations(5)
76+
// .forks(1)
77+
// .build();
78+
// new Runner(opt).run();
79+
// }
80+
6481
@Benchmark
6582
public void jsoniter(Blackhole bh) throws IOException {
6683
iter.reset(inputBytes);
6784
bh.consume(iter.read(modelTypeLiteral));
6885
}
6986

70-
@Benchmark
87+
// @Benchmark
7188
public void jsoniter_easy_mode(Blackhole bh) throws IOException {
7289
bh.consume(JsonIterator.deserialize(inputBytes, Model.class));
7390
}
7491

75-
@Benchmark
92+
// @Benchmark
7693
public void fastjson(Blackhole bh) throws IOException {
7794
// this is not a exactly fair comparison,
7895
// as string => object is not
7996
// bytes => object
8097
bh.consume(JSON.parseObject(input, Model.class));
8198
}
8299

83-
@Benchmark
100+
// @Benchmark
84101
public void jackson(Blackhole bh) throws IOException {
85102
bh.consume(jackson.readValue(inputBytes, modelTypeReference));
86103
}

src/main/java/com/jsoniter/CodegenAccess.java

Lines changed: 23 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public static void setExistingObject(JsonIterator iter, Object obj) {
3737
}
3838

3939
public static byte nextToken(JsonIterator iter) throws IOException {
40-
return iter.nextToken();
40+
return IterImpl.nextToken(iter);
4141
}
4242

4343
public static final <T> T read(JsonIterator iter, TypeLiteral<T> typeLiteral) throws IOException {
@@ -107,29 +107,29 @@ public static final <T> T read(String cacheKey, JsonIterator iter) throws IOExce
107107
}
108108

109109
public static boolean readArrayStart(JsonIterator iter) throws IOException {
110-
byte c = iter.nextToken();
111-
if (c != '[') {
112-
throw iter.reportError("readArrayStart", "expect [ or n");
113-
}
114-
c = iter.nextToken();
115-
if (c == ']') {
116-
return false;
110+
byte c = IterImpl.nextToken(iter);
111+
if (c == '[') {
112+
c = IterImpl.nextToken(iter);
113+
if (c == ']') {
114+
return false;
115+
}
116+
iter.unreadByte();
117+
return true;
117118
}
118-
iter.unreadByte();
119-
return true;
119+
throw iter.reportError("readArrayStart", "expect [ or n");
120120
}
121121

122122
public static boolean readObjectStart(JsonIterator iter) throws IOException {
123-
byte c = iter.nextToken();
124-
if (c != '{') {
125-
throw iter.reportError("readObjectStart", "expect { or n, found: " + (char) c);
126-
}
127-
c = iter.nextToken();
128-
if (c == '}') {
129-
return false;
123+
byte c = IterImpl.nextToken(iter);
124+
if (c == '{') {
125+
c = IterImpl.nextToken(iter);
126+
if (c == '}') {
127+
return false;
128+
}
129+
iter.unreadByte();
130+
return true;
130131
}
131-
iter.unreadByte();
132-
return true;
132+
throw iter.reportError("readObjectStart", "expect { or n, found: " + (char) c);
133133
}
134134

135135
public static void reportIncompleteObject(JsonIterator iter) {
@@ -142,66 +142,21 @@ public static void reportIncompleteArray(JsonIterator iter) {
142142

143143
public static final String readObjectFieldAsString(JsonIterator iter) throws IOException {
144144
String field = iter.readString();
145-
if (iter.nextToken() != ':') {
145+
if (IterImpl.nextToken(iter) != ':') {
146146
throw iter.reportError("readObjectFieldAsString", "expect :");
147147
}
148148
return field;
149149
}
150150

151151
public static final int readObjectFieldAsHash(JsonIterator iter) throws IOException {
152-
if (iter.nextToken() != '"') {
153-
throw iter.reportError("readObjectFieldAsHash", "expect \"");
154-
}
155-
long hash = 0x811c9dc5;
156-
for (; ; ) {
157-
byte c = 0;
158-
int i = iter.head;
159-
for (; i < iter.tail; i++) {
160-
c = iter.buf[i];
161-
if (c == '"') {
162-
break;
163-
}
164-
hash ^= c;
165-
hash *= 0x1000193;
166-
}
167-
if (c == '"') {
168-
iter.head = i + 1;
169-
if (iter.nextToken() != ':') {
170-
throw iter.reportError("readObjectFieldAsHash", "expect :");
171-
}
172-
return (int) hash;
173-
}
174-
if (!iter.loadMore()) {
175-
throw iter.reportError("readObjectFieldAsHash", "unmatched quote");
176-
}
177-
}
152+
return IterImpl.readObjectFieldAsHash(iter);
178153
}
179154

180155
public static final Slice readObjectFieldAsSlice(JsonIterator iter) throws IOException {
181-
if (iter.nextToken() != '"') {
182-
throw iter.reportError("readObjectFieldAsSlice", "expect \"");
183-
}
184-
Slice field = IterImplString.readSlice(iter);
185-
boolean notCopied = field != null;
186-
if (skipWhitespacesWithoutLoadMore(iter)) {
187-
if (notCopied) {
188-
int len = field.tail() - field.head();
189-
byte[] newBuf = new byte[len];
190-
System.arraycopy(field.data(), field.head(), newBuf, 0, len);
191-
field.reset(newBuf, 0, newBuf.length);
192-
}
193-
if (!iter.loadMore()) {
194-
throw iter.reportError("readObjectFieldAsSlice", "expect : after object field");
195-
}
196-
}
197-
if (iter.buf[iter.head] != ':') {
198-
throw iter.reportError("readObjectFieldAsSlice", "expect : after object field");
199-
}
200-
iter.head++;
201-
return field;
156+
return IterImpl.readObjectFieldAsSlice(iter);
202157
}
203158

204-
private final static boolean skipWhitespacesWithoutLoadMore(JsonIterator iter) throws IOException {
159+
final static boolean skipWhitespacesWithoutLoadMore(JsonIterator iter) throws IOException {
205160
for (int i = iter.head; i < iter.tail; i++) {
206161
byte c = iter.buf[i];
207162
switch (c) {

src/main/java/com/jsoniter/DynamicCodegen.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,10 @@ public static Decoder gen(String cacheKey, String source) throws Exception {
2727
decoder = (Decoder) ctClass.toClass().newInstance();
2828
return decoder;
2929
}
30+
31+
public static void enableStreamingSupport() throws Exception {
32+
CtClass ctClass = pool.makeClass("com.jsoniter.IterImpl");
33+
ctClass.setSuperclass(pool.get(IterImplForStreaming.class.getName()));
34+
ctClass.toClass();
35+
}
3036
}

0 commit comments

Comments
 (0)