Skip to content

Commit 272f8fa

Browse files
authored
Merge pull request #3921 from graphql-java/benchmark-large-in-memory-query
Large in memory query benchmark
2 parents 0c9e454 + f1730cc commit 272f8fa

File tree

1 file changed

+140
-0
lines changed

1 file changed

+140
-0
lines changed
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package performance;
2+
3+
import benchmark.BenchmarkUtils;
4+
import graphql.GraphQL;
5+
import graphql.schema.GraphQLSchema;
6+
import graphql.schema.idl.RuntimeWiring;
7+
import graphql.schema.idl.SchemaGenerator;
8+
import graphql.schema.idl.SchemaParser;
9+
import graphql.schema.idl.TypeDefinitionRegistry;
10+
import org.openjdk.jmh.annotations.Benchmark;
11+
import org.openjdk.jmh.annotations.BenchmarkMode;
12+
import org.openjdk.jmh.annotations.Fork;
13+
import org.openjdk.jmh.annotations.Level;
14+
import org.openjdk.jmh.annotations.Measurement;
15+
import org.openjdk.jmh.annotations.Mode;
16+
import org.openjdk.jmh.annotations.OutputTimeUnit;
17+
import org.openjdk.jmh.annotations.Scope;
18+
import org.openjdk.jmh.annotations.Setup;
19+
import org.openjdk.jmh.annotations.State;
20+
import org.openjdk.jmh.annotations.TearDown;
21+
import org.openjdk.jmh.annotations.Warmup;
22+
import org.openjdk.jmh.profile.GCProfiler;
23+
import org.openjdk.jmh.runner.Runner;
24+
import org.openjdk.jmh.runner.options.Options;
25+
import org.openjdk.jmh.runner.options.OptionsBuilder;
26+
27+
import java.util.List;
28+
import java.util.concurrent.TimeUnit;
29+
import java.util.stream.Collectors;
30+
import java.util.stream.IntStream;
31+
32+
import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring;
33+
34+
/**
35+
* This benchmark is an attempt to have a large in memory query that involves only sync work but lots of
36+
* data fetching invocation
37+
* <p>
38+
* It can also be run in a forever mode say if you want to connect a profiler to it say
39+
*/
40+
@State(Scope.Benchmark)
41+
@Warmup(iterations = 2, time = 5)
42+
@Measurement(iterations = 2)
43+
@Fork(2)
44+
public class LargeInMemoryQueryPerformance {
45+
46+
GraphQL graphQL;
47+
volatile boolean shutDown;
48+
49+
@Setup(Level.Trial)
50+
public void setUp() {
51+
shutDown = false;
52+
graphQL = buildGraphQL();
53+
}
54+
55+
@TearDown(Level.Trial)
56+
public void tearDown() {
57+
shutDown = true;
58+
}
59+
60+
61+
@Benchmark
62+
@BenchmarkMode(Mode.Throughput)
63+
@OutputTimeUnit(TimeUnit.SECONDS)
64+
public Object benchMarkSimpleQueriesThroughput() {
65+
return runManyQueriesToCompletion();
66+
}
67+
68+
@Benchmark
69+
@BenchmarkMode(Mode.AverageTime)
70+
@OutputTimeUnit(TimeUnit.SECONDS)
71+
public Object benchMarkSimpleQueriesAvgTime() {
72+
return runManyQueriesToCompletion();
73+
}
74+
75+
76+
public static void main(String[] args) throws Exception {
77+
// just to make sure it's all valid before testing
78+
runAtStartup();
79+
80+
Options opt = new OptionsBuilder()
81+
.include("performance.LargeInMemoryQueryBenchmark")
82+
.addProfiler(GCProfiler.class)
83+
.build();
84+
85+
new Runner(opt).run();
86+
}
87+
88+
private static void runAtStartup() {
89+
90+
LargeInMemoryQueryPerformance complexQueryBenchmark = new LargeInMemoryQueryPerformance();
91+
BenchmarkUtils.runInToolingForSomeTimeThenExit(
92+
complexQueryBenchmark::setUp,
93+
complexQueryBenchmark::runManyQueriesToCompletion,
94+
complexQueryBenchmark::tearDown
95+
96+
);
97+
}
98+
99+
100+
private Object runManyQueriesToCompletion() {
101+
return graphQL.execute(
102+
"query {\n" +
103+
"\n" +
104+
" giveMeLargeResponse {\n" +
105+
" someValue\n" +
106+
" }\n" +
107+
"}"
108+
);
109+
}
110+
111+
private static final List<SomeWrapper> manyObjects = IntStream
112+
.range(0, 10_000_000)
113+
.mapToObj(i -> new SomeWrapper("value #" + i))
114+
.collect(Collectors.toList());
115+
116+
public static class SomeWrapper {
117+
String someValue;
118+
119+
public SomeWrapper(String someValue) {
120+
this.someValue = someValue;
121+
}
122+
}
123+
124+
private GraphQL buildGraphQL() {
125+
TypeDefinitionRegistry typeDefinitionRegistry = new SchemaParser().parse("\n" +
126+
"type Query {\n" +
127+
" giveMeLargeResponse: [SomeWrapper]\n" +
128+
"}\n" +
129+
"type SomeWrapper {\n" +
130+
" someValue: String\n" +
131+
"}\n"
132+
);
133+
RuntimeWiring wiring = RuntimeWiring.newRuntimeWiring()
134+
.type(newTypeWiring("Query")
135+
.dataFetcher("giveMeLargeResponse", env -> manyObjects))
136+
.build();
137+
GraphQLSchema schema = new SchemaGenerator().makeExecutableSchema(typeDefinitionRegistry, wiring);
138+
return GraphQL.newGraphQL(schema).build();
139+
}
140+
}

0 commit comments

Comments
 (0)