Skip to content
Merged
Changes from 1 commit
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
Next Next commit
Large in memory query benchmark
  • Loading branch information
bbakerman committed Apr 20, 2025
commit bf441dee9ec931196741347bced51c42fd483ff6
139 changes: 139 additions & 0 deletions src/test/java/benchmark/LargeInMemoryQueryBenchmark.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package benchmark;

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 LargeInMemoryQueryBenchmark {

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("benchmark.LargeInMemoryQueryBenchmark")
.addProfiler(GCProfiler.class)
.build();

new Runner(opt).run();
}

private static void runAtStartup() {

LargeInMemoryQueryBenchmark complexQueryBenchmark = new LargeInMemoryQueryBenchmark();
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();
}
}