Measures the graphql-java engine's core execution overhead (field resolution, type checking, result building) with a balanced, realistic workload while minimising data-fetching work. Schema: 20 object types across 4 depth levels (5 types per level). Query shape: ~530 queried fields, ~2000 result
| 56 | * DataLoader (child fields resolved via batched DataLoader calls). |
| 57 | */ |
| 58 | @Warmup(iterations = 2, time = 5) |
| 59 | @Measurement(iterations = 3) |
| 60 | @Fork(2) |
| 61 | public class ExecutionBenchmark { |
| 62 | |
| 63 | // 4 levels of object types below Query → total query depth = 5 |
| 64 | private static final int LEVELS = 4; |
| 65 | // 5 types per level = 20 types total |
| 66 | private static final int TYPES_PER_LEVEL = 5; |
| 67 | // Intermediate types: 5 scalar fields + child_a + child_b = 7 selections |
| 68 | private static final int SCALAR_FIELDS = 5; |
| 69 | // Leaf types: 7 scalar fields |
| 70 | private static final int LEAF_SCALAR_FIELDS = 7; |
| 71 | // Query: 5 top-level fields (2 single + 3 list) |
| 72 | private static final int QUERY_FIELDS = 5; |
| 73 | private static final int QUERY_SINGLE_COUNT = 2; |
| 74 | // List fields return 2 items each |
| 75 | private static final int LIST_SIZE = 2; |
| 76 | |
| 77 | // Schema types shared by both variants: types[0] = L4 (leaf), types[LEVELS-1] = L1 |
| 78 | private static final GraphQLObjectType[][] schemaTypes = buildSchemaTypes(); |
| 79 | private static final GraphQLObjectType queryType = buildQueryType(); |
| 80 | static final String query = mkQuery(); |
| 81 | private static final String queryId = "exec-benchmark-query"; |
| 82 | |
| 83 | // ---- Baseline variant (PropertyDataFetcher with embedded Maps) ---- |
| 84 | static final GraphQL graphQL = buildGraphQL(); |
| 85 | |
| 86 | // ---- DataLoader variant ---- |
| 87 | // levelStores[i] holds all DTOs at schema level i+1 (index 0 = L1, 3 = L4) |
| 88 | @SuppressWarnings("unchecked") |
| 89 | private static final Map<String, Map<String, Object>>[] levelStores = new Map[LEVELS]; |
| 90 | static { |
| 91 | for (int i = 0; i < LEVELS; i++) { |
| 92 | levelStores[i] = new HashMap<>(); |
| 93 | } |
| 94 | } |
| 95 | static final GraphQL graphQLWithDL = buildGraphQLWithDataLoader(); |
| 96 | private static final ExecutorService batchLoadExecutor = Executors.newCachedThreadPool(); |
| 97 | private static final BatchLoader<String, Map<String, Object>> batchLoaderL2 = |
| 98 | keys -> CompletableFuture.supplyAsync( |
| 99 | () -> keys.stream().map(k -> levelStores[1].get(k)).collect(Collectors.toList()), |
| 100 | batchLoadExecutor); |
| 101 | private static final BatchLoader<String, Map<String, Object>> batchLoaderL3 = |
| 102 | keys -> CompletableFuture.supplyAsync( |
| 103 | () -> keys.stream().map(k -> levelStores[2].get(k)).collect(Collectors.toList()), |
| 104 | batchLoadExecutor); |
| 105 | private static final BatchLoader<String, Map<String, Object>> batchLoaderL4 = |
| 106 | keys -> CompletableFuture.supplyAsync( |
| 107 | () -> keys.stream().map(k -> levelStores[3].get(k)).collect(Collectors.toList()), |
| 108 | batchLoadExecutor); |
| 109 | |
| 110 | // ================ Benchmark methods ================ |
| 111 | |
| 112 | @Benchmark |
| 113 | @BenchmarkMode(Mode.Throughput) |
| 114 | @OutputTimeUnit(TimeUnit.SECONDS) |
| 115 | public ExecutionResult benchmarkThroughput() { |
nothing calls this directly
no test coverage detected
searching dependent graphs…