Skip to content

Commit 5e7dd4f

Browse files
authored
Merge pull request #268 from mrhenry/benchmarks
Add benchmarks
2 parents 363d9c3 + 4c66ed6 commit 5e7dd4f

File tree

4 files changed

+379
-1
lines changed

4 files changed

+379
-1
lines changed

benchutil/list_schema.go

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package benchutil
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/graphql-go/graphql"
7+
)
8+
9+
type color struct {
10+
Hex string
11+
R int
12+
G int
13+
B int
14+
}
15+
16+
func ListSchemaWithXItems(x int) graphql.Schema {
17+
18+
list := generateXListItems(x)
19+
20+
color := graphql.NewObject(graphql.ObjectConfig{
21+
Name: "Color",
22+
Description: "A color",
23+
Fields: graphql.Fields{
24+
"hex": &graphql.Field{
25+
Type: graphql.NewNonNull(graphql.String),
26+
Description: "Hex color code.",
27+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
28+
if c, ok := p.Source.(color); ok {
29+
return c.Hex, nil
30+
}
31+
return nil, nil
32+
},
33+
},
34+
"r": &graphql.Field{
35+
Type: graphql.NewNonNull(graphql.Int),
36+
Description: "Red value.",
37+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
38+
if c, ok := p.Source.(color); ok {
39+
return c.R, nil
40+
}
41+
return nil, nil
42+
},
43+
},
44+
"g": &graphql.Field{
45+
Type: graphql.NewNonNull(graphql.Int),
46+
Description: "Green value.",
47+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
48+
if c, ok := p.Source.(color); ok {
49+
return c.G, nil
50+
}
51+
return nil, nil
52+
},
53+
},
54+
"b": &graphql.Field{
55+
Type: graphql.NewNonNull(graphql.Int),
56+
Description: "Blue value.",
57+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
58+
if c, ok := p.Source.(color); ok {
59+
return c.B, nil
60+
}
61+
return nil, nil
62+
},
63+
},
64+
},
65+
})
66+
67+
queryType := graphql.NewObject(graphql.ObjectConfig{
68+
Name: "Query",
69+
Fields: graphql.Fields{
70+
"colors": {
71+
Type: graphql.NewList(color),
72+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
73+
return list, nil
74+
},
75+
},
76+
},
77+
})
78+
79+
colorSchema, _ := graphql.NewSchema(graphql.SchemaConfig{
80+
Query: queryType,
81+
})
82+
83+
return colorSchema
84+
}
85+
86+
var colors []color
87+
88+
func init() {
89+
colors = make([]color, 0, 256*16*16)
90+
91+
for r := 0; r < 256; r++ {
92+
for g := 0; g < 16; g++ {
93+
for b := 0; b < 16; b++ {
94+
colors = append(colors, color{
95+
Hex: fmt.Sprintf("#%x%x%x", r, g, b),
96+
R: r,
97+
G: g,
98+
B: b,
99+
})
100+
}
101+
}
102+
}
103+
}
104+
105+
func generateXListItems(x int) []color {
106+
if x > len(colors) {
107+
x = len(colors)
108+
}
109+
return colors[0:x]
110+
}

benchutil/wide_schema.go

+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package benchutil
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/graphql-go/graphql"
7+
)
8+
9+
func WideSchemaWithXFieldsAndYItems(x int, y int) graphql.Schema {
10+
wide := graphql.NewObject(graphql.ObjectConfig{
11+
Name: "Wide",
12+
Description: "An object",
13+
Fields: generateXWideFields(x),
14+
})
15+
16+
queryType := graphql.NewObject(graphql.ObjectConfig{
17+
Name: "Query",
18+
Fields: graphql.Fields{
19+
"wide": {
20+
Type: graphql.NewList(wide),
21+
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
22+
out := make([]struct{}, 0, y)
23+
for i := 0; i < y; i++ {
24+
out = append(out, struct{}{})
25+
}
26+
return out, nil
27+
},
28+
},
29+
},
30+
})
31+
32+
wideSchema, _ := graphql.NewSchema(graphql.SchemaConfig{
33+
Query: queryType,
34+
})
35+
36+
return wideSchema
37+
}
38+
39+
func generateXWideFields(x int) graphql.Fields {
40+
fields := graphql.Fields{}
41+
for i := 0; i < x; i++ {
42+
fields[generateFieldNameFromX(i)] = generateWideFieldFromX(i)
43+
}
44+
return fields
45+
}
46+
47+
func generateWideFieldFromX(x int) *graphql.Field {
48+
return &graphql.Field{
49+
Type: generateWideTypeFromX(x),
50+
Resolve: generateWideResolveFromX(x),
51+
}
52+
}
53+
54+
func generateWideTypeFromX(x int) graphql.Type {
55+
switch x % 8 {
56+
case 0:
57+
return graphql.String
58+
case 1:
59+
return graphql.NewNonNull(graphql.String)
60+
case 2:
61+
return graphql.Int
62+
case 3:
63+
return graphql.NewNonNull(graphql.Int)
64+
case 4:
65+
return graphql.Float
66+
case 5:
67+
return graphql.NewNonNull(graphql.Float)
68+
case 6:
69+
return graphql.Boolean
70+
case 7:
71+
return graphql.NewNonNull(graphql.Boolean)
72+
}
73+
74+
return nil
75+
}
76+
77+
func generateFieldNameFromX(x int) string {
78+
var out string
79+
alphabet := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "z"}
80+
v := x
81+
for {
82+
r := v % 10
83+
out = alphabet[r] + out
84+
v = v / 10
85+
if v == 0 {
86+
break
87+
}
88+
}
89+
return out
90+
}
91+
92+
func generateWideResolveFromX(x int) func(p graphql.ResolveParams) (interface{}, error) {
93+
switch x % 8 {
94+
case 0:
95+
return func(p graphql.ResolveParams) (interface{}, error) {
96+
return fmt.Sprint(x), nil
97+
}
98+
case 1:
99+
return func(p graphql.ResolveParams) (interface{}, error) {
100+
return fmt.Sprint(x), nil
101+
}
102+
case 2:
103+
return func(p graphql.ResolveParams) (interface{}, error) {
104+
return x, nil
105+
}
106+
case 3:
107+
return func(p graphql.ResolveParams) (interface{}, error) {
108+
return x, nil
109+
}
110+
case 4:
111+
return func(p graphql.ResolveParams) (interface{}, error) {
112+
return float64(x), nil
113+
}
114+
case 5:
115+
return func(p graphql.ResolveParams) (interface{}, error) {
116+
return float64(x), nil
117+
}
118+
case 6:
119+
return func(p graphql.ResolveParams) (interface{}, error) {
120+
if x%2 == 0 {
121+
return false, nil
122+
}
123+
return true, nil
124+
}
125+
case 7:
126+
return func(p graphql.ResolveParams) (interface{}, error) {
127+
if x%2 == 0 {
128+
return false, nil
129+
}
130+
return true, nil
131+
}
132+
}
133+
134+
return nil
135+
}
136+
137+
func WideSchemaQuery(x int) string {
138+
var fields string
139+
for i := 0; i < x; i++ {
140+
fields = fields + generateFieldNameFromX(i) + " "
141+
}
142+
143+
return fmt.Sprintf("query { wide { %s} }", fields)
144+
}

graphql_bench_test.go

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package graphql_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/graphql-go/graphql"
7+
"github.com/graphql-go/graphql/benchutil"
8+
)
9+
10+
type B struct {
11+
Query string
12+
Schema graphql.Schema
13+
}
14+
15+
func benchGraphql(bench B, p graphql.Params, t testing.TB) {
16+
result := graphql.Do(p)
17+
if len(result.Errors) > 0 {
18+
t.Fatalf("wrong result, unexpected errors: %v", result.Errors)
19+
}
20+
}
21+
22+
// Benchmark a reasonably large list of small items.
23+
func BenchmarkListQuery_1(b *testing.B) {
24+
nItemsListQueryBenchmark(1)(b)
25+
}
26+
27+
func BenchmarkListQuery_100(b *testing.B) {
28+
nItemsListQueryBenchmark(100)(b)
29+
}
30+
31+
func BenchmarkListQuery_1K(b *testing.B) {
32+
nItemsListQueryBenchmark(1000)(b)
33+
}
34+
35+
func BenchmarkListQuery_10K(b *testing.B) {
36+
nItemsListQueryBenchmark(10 * 1000)(b)
37+
}
38+
39+
func BenchmarkListQuery_100K(b *testing.B) {
40+
nItemsListQueryBenchmark(100 * 1000)(b)
41+
}
42+
43+
func nItemsListQueryBenchmark(x int) func(b *testing.B) {
44+
return func(b *testing.B) {
45+
schema := benchutil.ListSchemaWithXItems(x)
46+
47+
bench := B{
48+
Query: `
49+
query {
50+
colors {
51+
hex
52+
r
53+
g
54+
b
55+
}
56+
}
57+
`,
58+
Schema: schema,
59+
}
60+
61+
for i := 0; i < b.N; i++ {
62+
63+
params := graphql.Params{
64+
Schema: schema,
65+
RequestString: bench.Query,
66+
}
67+
benchGraphql(bench, params, b)
68+
}
69+
}
70+
}
71+
72+
func BenchmarkWideQuery_1_1(b *testing.B) {
73+
nFieldsyItemsQueryBenchmark(1, 1)(b)
74+
}
75+
76+
func BenchmarkWideQuery_10_1(b *testing.B) {
77+
nFieldsyItemsQueryBenchmark(10, 1)(b)
78+
}
79+
80+
func BenchmarkWideQuery_100_1(b *testing.B) {
81+
nFieldsyItemsQueryBenchmark(100, 1)(b)
82+
}
83+
84+
func BenchmarkWideQuery_1K_1(b *testing.B) {
85+
nFieldsyItemsQueryBenchmark(1000, 1)(b)
86+
}
87+
88+
func BenchmarkWideQuery_1_10(b *testing.B) {
89+
nFieldsyItemsQueryBenchmark(1, 10)(b)
90+
}
91+
92+
func BenchmarkWideQuery_10_10(b *testing.B) {
93+
nFieldsyItemsQueryBenchmark(10, 10)(b)
94+
}
95+
96+
func BenchmarkWideQuery_100_10(b *testing.B) {
97+
nFieldsyItemsQueryBenchmark(100, 10)(b)
98+
}
99+
100+
func BenchmarkWideQuery_1K_10(b *testing.B) {
101+
nFieldsyItemsQueryBenchmark(1000, 10)(b)
102+
}
103+
104+
func nFieldsyItemsQueryBenchmark(x int, y int) func(b *testing.B) {
105+
return func(b *testing.B) {
106+
schema := benchutil.WideSchemaWithXFieldsAndYItems(x, y)
107+
query := benchutil.WideSchemaQuery(x)
108+
109+
bench := B{
110+
Query: query,
111+
Schema: schema,
112+
}
113+
114+
b.ResetTimer()
115+
116+
for i := 0; i < b.N; i++ {
117+
params := graphql.Params{
118+
Schema: schema,
119+
RequestString: bench.Query,
120+
}
121+
benchGraphql(bench, params, b)
122+
}
123+
}
124+
}

testutil/testutil.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ func init() {
302302
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
303303
id, err := strconv.Atoi(p.Args["id"].(string))
304304
if err != nil {
305-
return nil, err
305+
return nil, err
306306
}
307307
return GetHuman(id), nil
308308
},

0 commit comments

Comments
 (0)