From 6937fbb32a61f2c70060c1a9417aeb0b8750feb9 Mon Sep 17 00:00:00 2001 From: Andreas Marek Date: Mon, 24 Feb 2025 07:43:51 +1000 Subject: [PATCH] add more performance tests --- ...OverlappingFieldValidationPerformance.java | 164 +++++++++++++++++- 1 file changed, 161 insertions(+), 3 deletions(-) diff --git a/src/test/java/performance/OverlappingFieldValidationPerformance.java b/src/test/java/performance/OverlappingFieldValidationPerformance.java index 77a2af6aec..e95cc83a09 100644 --- a/src/test/java/performance/OverlappingFieldValidationPerformance.java +++ b/src/test/java/performance/OverlappingFieldValidationPerformance.java @@ -19,6 +19,7 @@ import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; @@ -38,15 +39,42 @@ @Fork(3) public class OverlappingFieldValidationPerformance { + + static String schemaSdl = " type Query { viewer: Viewer } interface Abstract { field: Abstract leaf: Int } interface Abstract1 { field: Abstract leaf: Int } interface Abstract2 { field: Abstract leaf: Int }" + + " type Concrete1 implements Abstract1{ field: Abstract leaf: Int} " + + "type Concrete2 implements Abstract2{ field: Abstract leaf: Int} " + + "type Viewer { xingId: XingId } type XingId { firstName: String! lastName: String! }"; + @State(Scope.Benchmark) public static class MyState { GraphQLSchema schema; + GraphQLSchema schema2; Document document; + @Param({"2", "10", "100"}) + int size; + + Document overlapFrag; + Document overlapNoFrag; + Document noOverlapFrag; + Document noOverlapNoFrag; + Document repeatedFields; + Document deepAbstractConcrete; + @Setup public void setup() { try { + overlapFrag = makeQuery(size, true, true); + overlapNoFrag = makeQuery(size, true, false); + noOverlapFrag = makeQuery(size, false, true); + noOverlapNoFrag = makeQuery(size, false, false); + repeatedFields = makeRepeatedFieldsQuery(size); + deepAbstractConcrete = makeDeepAbstractConcreteQuery(size); + + + schema2 = SchemaGenerator.createdMockedSchema(schemaSdl); + String schemaString = PerformanceTestingUtils.loadResource("large-schema-4.graphqls"); String query = PerformanceTestingUtils.loadResource("large-schema-4-query.graphql"); schema = SchemaGenerator.createdMockedSchema(schemaString); @@ -64,14 +92,58 @@ public void setup() { @Benchmark @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) public void overlappingFieldValidationAbgTime(MyState myState, Blackhole blackhole) { - blackhole.consume(validateQuery(myState.schema, myState.document)); + blackhole.consume(validateQuery(myState.schema2, myState.document)); } @Benchmark - @OutputTimeUnit(TimeUnit.SECONDS) + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) public void overlappingFieldValidationThroughput(MyState myState, Blackhole blackhole) { - blackhole.consume(validateQuery(myState.schema, myState.document)); + blackhole.consume(validateQuery(myState.schema2, myState.document)); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public void benchmarkRepeatedFields(MyState myState, Blackhole blackhole) { + blackhole.consume(validateQuery(myState.schema2, myState.repeatedFields)); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public void benchmarkOverlapFrag(MyState myState, Blackhole blackhole) { + blackhole.consume(validateQuery(myState.schema2, myState.overlapFrag)); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public void benchmarkOverlapNoFrag(MyState myState, Blackhole blackhole) { + blackhole.consume(validateQuery(myState.schema2, myState.overlapNoFrag)); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public void benchmarkNoOverlapFrag(MyState myState, Blackhole blackhole) { + blackhole.consume(validateQuery(myState.schema2, myState.noOverlapFrag)); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public void benchmarkNoOverlapNoFrag(MyState myState, Blackhole blackhole) { + blackhole.consume(validateQuery(myState.schema2, myState.noOverlapNoFrag)); + } + + @Benchmark + @BenchmarkMode(Mode.AverageTime) + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public void benchmarkDeepAbstractConcrete(MyState myState, Blackhole blackhole) { + blackhole.consume(validateQuery(myState.schema2, myState.deepAbstractConcrete)); } private List validateQuery(GraphQLSchema schema, Document document) { @@ -83,4 +155,90 @@ private List validateQuery(GraphQLSchema schema, Document docum languageTraversal.traverse(document, new RulesVisitor(validationContext, Collections.singletonList(overlappingFieldsCanBeMerged))); return errorCollector.getErrors(); } + + + private static Document makeQuery(int size, boolean overlapping, boolean fragments) { + if (fragments) { + return makeQueryWithFragments(size, overlapping); + } else { + return makeQueryWithoutFragments(size, overlapping); + } + } + + private static Document makeRepeatedFieldsQuery(int size) { + StringBuilder b = new StringBuilder(); + + b.append(" query testQuery { viewer { xingId {"); + + b.append("firstName\n".repeat(Math.max(0, size))); + + b.append("} } }"); + + return Parser.parse(b.toString()); + } + + + private static Document makeQueryWithFragments(int size, boolean overlapping) { + StringBuilder b = new StringBuilder(); + + for (int i = 1; i <= size; i++) { + if (overlapping) { + b.append(" fragment mergeIdenticalFields" + i + " on Query {viewer { xingId { firstName lastName }}}"); + } else { + b.append("fragment mergeIdenticalFields" + i + " on Query {viewer" + i + " { xingId" + i + " { firstName" + i + " lastName" + i + " } }}"); + } + + b.append("\n\n"); + } + + b.append("query testQuery {"); + for (int i = 1; i <= size; i++) { + b.append("...mergeIdenticalFields" + i + "\n"); + } + b.append("}"); + return Parser.parse(b.toString()); + } + + private static Document makeQueryWithoutFragments(int size, boolean overlapping) { + StringBuilder b = new StringBuilder(); + + b.append("query testQuery {"); + + for (int i = 1; i <= size; i++) { + if (overlapping) { + b.append(" viewer { xingId { firstName } } "); + } else { + b.append(" viewer" + i + " { xingId" + i + " { firstName" + i + " } } "); + } + + b.append("\n\n"); + } + + b.append("}"); + + return Parser.parse(b.toString()); + } + + private static Document makeDeepAbstractConcreteQuery(int depth) { + StringBuilder q = new StringBuilder(); + + q.append("fragment multiply on Whatever { field { " + + "... on Abstract1 { field { leaf } } " + + "... on Abstract2 { field { leaf } } " + + "... on Concrete1 { field { leaf } } " + + "... on Concrete2 { field { leaf } } } } " + + "query DeepAbstractConcrete { "); + + for (int i = 1; i <= depth; i++) { + q.append("field { ...multiply "); + } + + for (int i = 1; i <= depth; i++) { + q.append(" }"); + } + + q.append("\n}"); + + return Parser.parse(q.toString()); + } }