1919import org .openjdk .jmh .annotations .Measurement ;
2020import org .openjdk .jmh .annotations .Mode ;
2121import org .openjdk .jmh .annotations .OutputTimeUnit ;
22+ import org .openjdk .jmh .annotations .Param ;
2223import org .openjdk .jmh .annotations .Scope ;
2324import org .openjdk .jmh .annotations .Setup ;
2425import org .openjdk .jmh .annotations .State ;
3839@ Fork (3 )
3940public class OverlappingFieldValidationPerformance {
4041
42+
43+ 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 }" +
44+ " type Concrete1 implements Abstract1{ field: Abstract leaf: Int} " +
45+ "type Concrete2 implements Abstract2{ field: Abstract leaf: Int} " +
46+ "type Viewer { xingId: XingId } type XingId { firstName: String! lastName: String! }" ;
47+
4148 @ State (Scope .Benchmark )
4249 public static class MyState {
4350
4451 GraphQLSchema schema ;
52+ GraphQLSchema schema2 ;
4553 Document document ;
4654
55+ @ Param ({"2" , "10" , "100" })
56+ int size ;
57+
58+ Document overlapFrag ;
59+ Document overlapNoFrag ;
60+ Document noOverlapFrag ;
61+ Document noOverlapNoFrag ;
62+ Document repeatedFields ;
63+ Document deepAbstractConcrete ;
64+
4765 @ Setup
4866 public void setup () {
4967 try {
68+ overlapFrag = makeQuery (size , true , true );
69+ overlapNoFrag = makeQuery (size , true , false );
70+ noOverlapFrag = makeQuery (size , false , true );
71+ noOverlapNoFrag = makeQuery (size , false , false );
72+ repeatedFields = makeRepeatedFieldsQuery (size );
73+ deepAbstractConcrete = makeDeepAbstractConcreteQuery (size );
74+
75+
76+ schema2 = SchemaGenerator .createdMockedSchema (schemaSdl );
77+
5078 String schemaString = PerformanceTestingUtils .loadResource ("large-schema-4.graphqls" );
5179 String query = PerformanceTestingUtils .loadResource ("large-schema-4-query.graphql" );
5280 schema = SchemaGenerator .createdMockedSchema (schemaString );
@@ -64,14 +92,58 @@ public void setup() {
6492
6593 @ Benchmark
6694 @ BenchmarkMode (Mode .AverageTime )
95+ @ OutputTimeUnit (TimeUnit .NANOSECONDS )
6796 public void overlappingFieldValidationAbgTime (MyState myState , Blackhole blackhole ) {
68- blackhole .consume (validateQuery (myState .schema , myState .document ));
97+ blackhole .consume (validateQuery (myState .schema2 , myState .document ));
6998 }
7099
71100 @ Benchmark
72- @ OutputTimeUnit (TimeUnit .SECONDS )
101+ @ BenchmarkMode (Mode .AverageTime )
102+ @ OutputTimeUnit (TimeUnit .NANOSECONDS )
73103 public void overlappingFieldValidationThroughput (MyState myState , Blackhole blackhole ) {
74- blackhole .consume (validateQuery (myState .schema , myState .document ));
104+ blackhole .consume (validateQuery (myState .schema2 , myState .document ));
105+ }
106+
107+ @ Benchmark
108+ @ BenchmarkMode (Mode .AverageTime )
109+ @ OutputTimeUnit (TimeUnit .NANOSECONDS )
110+ public void benchmarkRepeatedFields (MyState myState , Blackhole blackhole ) {
111+ blackhole .consume (validateQuery (myState .schema2 , myState .repeatedFields ));
112+ }
113+
114+ @ Benchmark
115+ @ BenchmarkMode (Mode .AverageTime )
116+ @ OutputTimeUnit (TimeUnit .NANOSECONDS )
117+ public void benchmarkOverlapFrag (MyState myState , Blackhole blackhole ) {
118+ blackhole .consume (validateQuery (myState .schema2 , myState .overlapFrag ));
119+ }
120+
121+ @ Benchmark
122+ @ BenchmarkMode (Mode .AverageTime )
123+ @ OutputTimeUnit (TimeUnit .NANOSECONDS )
124+ public void benchmarkOverlapNoFrag (MyState myState , Blackhole blackhole ) {
125+ blackhole .consume (validateQuery (myState .schema2 , myState .overlapNoFrag ));
126+ }
127+
128+ @ Benchmark
129+ @ BenchmarkMode (Mode .AverageTime )
130+ @ OutputTimeUnit (TimeUnit .NANOSECONDS )
131+ public void benchmarkNoOverlapFrag (MyState myState , Blackhole blackhole ) {
132+ blackhole .consume (validateQuery (myState .schema2 , myState .noOverlapFrag ));
133+ }
134+
135+ @ Benchmark
136+ @ BenchmarkMode (Mode .AverageTime )
137+ @ OutputTimeUnit (TimeUnit .NANOSECONDS )
138+ public void benchmarkNoOverlapNoFrag (MyState myState , Blackhole blackhole ) {
139+ blackhole .consume (validateQuery (myState .schema2 , myState .noOverlapNoFrag ));
140+ }
141+
142+ @ Benchmark
143+ @ BenchmarkMode (Mode .AverageTime )
144+ @ OutputTimeUnit (TimeUnit .NANOSECONDS )
145+ public void benchmarkDeepAbstractConcrete (MyState myState , Blackhole blackhole ) {
146+ blackhole .consume (validateQuery (myState .schema2 , myState .deepAbstractConcrete ));
75147 }
76148
77149 private List <ValidationError > validateQuery (GraphQLSchema schema , Document document ) {
@@ -83,4 +155,90 @@ private List<ValidationError> validateQuery(GraphQLSchema schema, Document docum
83155 languageTraversal .traverse (document , new RulesVisitor (validationContext , Collections .singletonList (overlappingFieldsCanBeMerged )));
84156 return errorCollector .getErrors ();
85157 }
158+
159+
160+ private static Document makeQuery (int size , boolean overlapping , boolean fragments ) {
161+ if (fragments ) {
162+ return makeQueryWithFragments (size , overlapping );
163+ } else {
164+ return makeQueryWithoutFragments (size , overlapping );
165+ }
166+ }
167+
168+ private static Document makeRepeatedFieldsQuery (int size ) {
169+ StringBuilder b = new StringBuilder ();
170+
171+ b .append (" query testQuery { viewer { xingId {" );
172+
173+ b .append ("firstName\n " .repeat (Math .max (0 , size )));
174+
175+ b .append ("} } }" );
176+
177+ return Parser .parse (b .toString ());
178+ }
179+
180+
181+ private static Document makeQueryWithFragments (int size , boolean overlapping ) {
182+ StringBuilder b = new StringBuilder ();
183+
184+ for (int i = 1 ; i <= size ; i ++) {
185+ if (overlapping ) {
186+ b .append (" fragment mergeIdenticalFields" + i + " on Query {viewer { xingId { firstName lastName }}}" );
187+ } else {
188+ b .append ("fragment mergeIdenticalFields" + i + " on Query {viewer" + i + " { xingId" + i + " { firstName" + i + " lastName" + i + " } }}" );
189+ }
190+
191+ b .append ("\n \n " );
192+ }
193+
194+ b .append ("query testQuery {" );
195+ for (int i = 1 ; i <= size ; i ++) {
196+ b .append ("...mergeIdenticalFields" + i + "\n " );
197+ }
198+ b .append ("}" );
199+ return Parser .parse (b .toString ());
200+ }
201+
202+ private static Document makeQueryWithoutFragments (int size , boolean overlapping ) {
203+ StringBuilder b = new StringBuilder ();
204+
205+ b .append ("query testQuery {" );
206+
207+ for (int i = 1 ; i <= size ; i ++) {
208+ if (overlapping ) {
209+ b .append (" viewer { xingId { firstName } } " );
210+ } else {
211+ b .append (" viewer" + i + " { xingId" + i + " { firstName" + i + " } } " );
212+ }
213+
214+ b .append ("\n \n " );
215+ }
216+
217+ b .append ("}" );
218+
219+ return Parser .parse (b .toString ());
220+ }
221+
222+ private static Document makeDeepAbstractConcreteQuery (int depth ) {
223+ StringBuilder q = new StringBuilder ();
224+
225+ q .append ("fragment multiply on Whatever { field { " +
226+ "... on Abstract1 { field { leaf } } " +
227+ "... on Abstract2 { field { leaf } } " +
228+ "... on Concrete1 { field { leaf } } " +
229+ "... on Concrete2 { field { leaf } } } } " +
230+ "query DeepAbstractConcrete { " );
231+
232+ for (int i = 1 ; i <= depth ; i ++) {
233+ q .append ("field { ...multiply " );
234+ }
235+
236+ for (int i = 1 ; i <= depth ; i ++) {
237+ q .append (" }" );
238+ }
239+
240+ q .append ("\n }" );
241+
242+ return Parser .parse (q .toString ());
243+ }
86244}
0 commit comments