LargeInMemoryQueryPerformance.java
package performance;
import benchmark.BenchmarkUtils;
import graphql.GraphQL;
import graphql.schema.GraphQLSchema;
import graphql.schema.idl.RuntimeWiring;
import graphql.schema.idl.SchemaGenerator;
import graphql.schema.idl.SchemaParser;
import graphql.schema.idl.TypeDefinitionRegistry;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.profile.GCProfiler;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import static graphql.schema.idl.TypeRuntimeWiring.newTypeWiring;
/**
* This benchmark is an attempt to have a large in memory query that involves only sync work but lots of
* data fetching invocation
* <p>
* It can also be run in a forever mode say if you want to connect a profiler to it say
*/
@State(Scope.Benchmark)
@Warmup(iterations = 2, time = 5)
@Measurement(iterations = 2)
@Fork(2)
public class LargeInMemoryQueryPerformance {
GraphQL graphQL;
volatile boolean shutDown;
@Setup(Level.Trial)
public void setUp() {
shutDown = false;
graphQL = buildGraphQL();
}
@TearDown(Level.Trial)
public void tearDown() {
shutDown = true;
}
@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
public Object benchMarkSimpleQueriesThroughput() {
return runManyQueriesToCompletion();
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.SECONDS)
public Object benchMarkSimpleQueriesAvgTime() {
return runManyQueriesToCompletion();
}
public static void main(String[] args) throws Exception {
// just to make sure it's all valid before testing
runAtStartup();
Options opt = new OptionsBuilder()
.include("performance.LargeInMemoryQueryPerformance")
.addProfiler(GCProfiler.class)
.build();
new Runner(opt).run();
}
private static void runAtStartup() {
LargeInMemoryQueryPerformance complexQueryBenchmark = new LargeInMemoryQueryPerformance();
BenchmarkUtils.runInToolingForSomeTimeThenExit(
complexQueryBenchmark::setUp,
complexQueryBenchmark::runManyQueriesToCompletion,
complexQueryBenchmark::tearDown
);
}
private Object runManyQueriesToCompletion() {
return graphQL.execute(
"query {\n" +
"\n" +
" giveMeLargeResponse {\n" +
" someValue\n" +
" }\n" +
"}"
);
}
private static final List<SomeWrapper> manyObjects = IntStream
.range(0, 10_000_000)
.mapToObj(i -> new SomeWrapper("value #" + i))
.collect(Collectors.toList());
public static class SomeWrapper {
String someValue;
public SomeWrapper(String someValue) {
this.someValue = someValue;
}
}
private GraphQL buildGraphQL() {
TypeDefinitionRegistry typeDefinitionRegistry = new SchemaParser().parse("\n" +
"type Query {\n" +
" giveMeLargeResponse: [SomeWrapper]\n" +
"}\n" +
"type SomeWrapper {\n" +
" someValue: String\n" +
"}\n"
);
RuntimeWiring wiring = RuntimeWiring.newRuntimeWiring()
.type(newTypeWiring("Query")
.dataFetcher("giveMeLargeResponse", env -> manyObjects))
.build();
GraphQLSchema schema = new SchemaGenerator().makeExecutableSchema(typeDefinitionRegistry, wiring);
return GraphQL.newGraphQL(schema).build();
}
}