Skip to content

Add StringReader input benchmark #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 20, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.TimeValue;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
Expand Down Expand Up @@ -51,7 +56,8 @@ <F extends JsonFactory, B extends TSFBuilder<F, B>> B apply(B factory) {
<F extends JsonFactory, B extends TSFBuilder<F, B>> B apply(B factory) {
return factory.disable(JsonFactory.Feature.CANONICALIZE_FIELD_NAMES);
}
};
},
;

abstract <F extends JsonFactory, B extends TSFBuilder<F, B>> B apply(B factory);
}
Expand All @@ -62,38 +68,79 @@ <F extends JsonFactory, B extends TSFBuilder<F, B>> B apply(B factory) {
public enum InputType {
INPUT_STREAM() {
@Override
JsonParser create(JsonFactory factory, Supplier<String> jsonSupplier) throws IOException {
return factory.createParser(new ByteArrayInputStream(jsonSupplier.get().getBytes(StandardCharsets.UTF_8)));
JsonParser create(JsonFactory factory, Supplier<byte[]> bytesSupplier) throws IOException {
return factory.createParser(new ByteArrayInputStream(bytesSupplier.get()));
}
},
READER() {
@Override
JsonParser create(JsonFactory factory, Supplier<String> jsonSupplier) throws IOException {
// Instead of using 'new StringReader(jsonSupplier.get())', we construct an InputStreamReader
JsonParser create(JsonFactory factory, Supplier<byte[]> bytesSupplier) throws IOException {
// Instead of using 'new StringReader(bytesSupplier.get())', we construct an InputStreamReader
// to more closely match overhead of INPUT_STREAM for comparison.
return factory.createParser(new InputStreamReader(
new ByteArrayInputStream(jsonSupplier.get().getBytes(StandardCharsets.UTF_8)),
new ByteArrayInputStream(bytesSupplier.get()),
StandardCharsets.UTF_8));
}
};
},
STRING_READER() {
@Override
JsonParser create(JsonFactory factory, Supplier<byte[]> jsonSupplier) throws IOException {
StringReader reader = new StringReader(new String(jsonSupplier.get(), Charset.forName("UTF-8")));
return factory.createParser(reader);
}
},
;

abstract JsonParser create(JsonFactory factory, Supplier<String> jsonSupplier) throws IOException;
abstract JsonParser create(JsonFactory factory, Supplier<byte[]> jsonSupplier) throws IOException;
}

public enum InputShape {
KEY_MAP(
new TypeReference<Map<String, Boolean>>() {
},
() -> "{\"key\":true}"),
RANDOM_KEY_MAP(
new TypeReference<Map<String, Boolean>>() {},
new TypeReference<Map<String, Boolean>>() {
},
() -> "{\"" + ThreadLocalRandom.current().nextInt() + "\":true}"),
BEAN_WITH_RANDOM_KEY_MAP(
new TypeReference<SimpleClass>() {},
new TypeReference<SimpleClass>() {
},
() -> "{\"fieldWithMap\":{\"" + ThreadLocalRandom.current().nextInt()
+ "\":true},\"stringOne\":\"a\",\"stringTwo\":\"a\",\"stringThree\":\"a\"}");
+ "\":true},\"stringOne\":\"a\",\"stringTwo\":\"a\",\"stringThree\":\"a\"}"),
BEAN_WITH_LARGE_KEY_MAP(
new TypeReference<SimpleClass>() {
},
new Supplier<String>() {
private final String json = generateSimpleInstanceJson(10_000);

@Override
public String get() {
return json;
}
}
),
;

private static String generateSimpleInstanceJson(int n) {
StringBuilder builder = new StringBuilder();
builder.append("{\"fieldWithMap\":{");
for (int i = 0; i < n; i++) {
builder.append("\"").append(i).append("\":").append(i % 2 == 0);
if (i < n-1) {
builder.append(',');
}
}
builder.append("},\"stringOne\":\"a\",\"stringTwo\":\"a\",\"stringThree\":\"a\"}");
return builder.toString();
}

private final TypeReference<?> typereference;
private final Supplier<String> jsonSupplier;
private final Supplier<byte[]> bytesSupplier;

InputShape(TypeReference<?> typereference, Supplier<String> jsonSupplier) {
this.typereference = typereference;
this.jsonSupplier = jsonSupplier;
this.bytesSupplier = () -> jsonSupplier.get().getBytes(StandardCharsets.UTF_8);
}
}

Expand Down Expand Up @@ -121,7 +168,7 @@ public void setup() {

@Benchmark
public Object parse() throws IOException {
try (JsonParser parser = type.create(factory, shape.jsonSupplier)) {
try (JsonParser parser = type.create(factory, shape.bytesSupplier)) {
return reader.readValue(parser);
}
}
Expand All @@ -140,4 +187,16 @@ public static final class SimpleClass {
@JsonProperty("stringThree")
public String stringThree;
}

public static void main(String[] _args) throws Exception {
new Runner(new OptionsBuilder()
.include(JsonArbitraryFieldNameBenchmark.class.getName())
.warmupIterations(2)
.warmupTime(TimeValue.seconds(5))
.measurementIterations(4)
.measurementTime(TimeValue.seconds(5))
.mode(Mode.AverageTime)
.forks(1)
.build()).run();
}
}