1// Copyright 2011 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Large data benchmark.
6// The JSON data is a summary of agl's changes in the
7// go, webkit, and chromium open source projects.
8// We benchmark converting between the JSON form
9// and in-memory data structures.
10
11package json
12
13import (
14	"bytes"
15	"compress/gzip"
16	"io/ioutil"
17	"os"
18	"strings"
19	"testing"
20)
21
22type codeResponse struct {
23	Tree     *codeNode `json:"tree"`
24	Username string    `json:"username"`
25}
26
27type codeNode struct {
28	Name     string      `json:"name"`
29	Kids     []*codeNode `json:"kids"`
30	CLWeight float64     `json:"cl_weight"`
31	Touches  int         `json:"touches"`
32	MinT     int64       `json:"min_t"`
33	MaxT     int64       `json:"max_t"`
34	MeanT    int64       `json:"mean_t"`
35}
36
37var codeJSON []byte
38var codeStruct codeResponse
39
40func codeInit() {
41	f, err := os.Open("testdata/code.json.gz")
42	if err != nil {
43		panic(err)
44	}
45	defer f.Close()
46	gz, err := gzip.NewReader(f)
47	if err != nil {
48		panic(err)
49	}
50	data, err := ioutil.ReadAll(gz)
51	if err != nil {
52		panic(err)
53	}
54
55	codeJSON = data
56
57	if err := Unmarshal(codeJSON, &codeStruct); err != nil {
58		panic("unmarshal code.json: " + err.Error())
59	}
60
61	if data, err = Marshal(&codeStruct); err != nil {
62		panic("marshal code.json: " + err.Error())
63	}
64
65	if !bytes.Equal(data, codeJSON) {
66		println("different lengths", len(data), len(codeJSON))
67		for i := 0; i < len(data) && i < len(codeJSON); i++ {
68			if data[i] != codeJSON[i] {
69				println("re-marshal: changed at byte", i)
70				println("orig: ", string(codeJSON[i-10:i+10]))
71				println("new: ", string(data[i-10:i+10]))
72				break
73			}
74		}
75		panic("re-marshal code.json: different result")
76	}
77}
78
79func BenchmarkCodeEncoder(b *testing.B) {
80	if codeJSON == nil {
81		b.StopTimer()
82		codeInit()
83		b.StartTimer()
84	}
85	b.RunParallel(func(pb *testing.PB) {
86		enc := NewEncoder(ioutil.Discard)
87		for pb.Next() {
88			if err := enc.Encode(&codeStruct); err != nil {
89				b.Fatal("Encode:", err)
90			}
91		}
92	})
93	b.SetBytes(int64(len(codeJSON)))
94}
95
96func BenchmarkCodeMarshal(b *testing.B) {
97	if codeJSON == nil {
98		b.StopTimer()
99		codeInit()
100		b.StartTimer()
101	}
102	b.RunParallel(func(pb *testing.PB) {
103		for pb.Next() {
104			if _, err := Marshal(&codeStruct); err != nil {
105				b.Fatal("Marshal:", err)
106			}
107		}
108	})
109	b.SetBytes(int64(len(codeJSON)))
110}
111
112func BenchmarkCodeDecoder(b *testing.B) {
113	if codeJSON == nil {
114		b.StopTimer()
115		codeInit()
116		b.StartTimer()
117	}
118	b.RunParallel(func(pb *testing.PB) {
119		var buf bytes.Buffer
120		dec := NewDecoder(&buf)
121		var r codeResponse
122		for pb.Next() {
123			buf.Write(codeJSON)
124			// hide EOF
125			buf.WriteByte('\n')
126			buf.WriteByte('\n')
127			buf.WriteByte('\n')
128			if err := dec.Decode(&r); err != nil {
129				b.Fatal("Decode:", err)
130			}
131		}
132	})
133	b.SetBytes(int64(len(codeJSON)))
134}
135
136func BenchmarkUnicodeDecoder(b *testing.B) {
137	j := []byte(`"\uD83D\uDE01"`)
138	b.SetBytes(int64(len(j)))
139	r := bytes.NewReader(j)
140	dec := NewDecoder(r)
141	var out string
142	b.ResetTimer()
143	for i := 0; i < b.N; i++ {
144		if err := dec.Decode(&out); err != nil {
145			b.Fatal("Decode:", err)
146		}
147		r.Seek(0, 0)
148	}
149}
150
151func BenchmarkDecoderStream(b *testing.B) {
152	b.StopTimer()
153	var buf bytes.Buffer
154	dec := NewDecoder(&buf)
155	buf.WriteString(`"` + strings.Repeat("x", 1000000) + `"` + "\n\n\n")
156	var x interface{}
157	if err := dec.Decode(&x); err != nil {
158		b.Fatal("Decode:", err)
159	}
160	ones := strings.Repeat(" 1\n", 300000) + "\n\n\n"
161	b.StartTimer()
162	for i := 0; i < b.N; i++ {
163		if i%300000 == 0 {
164			buf.WriteString(ones)
165		}
166		x = nil
167		if err := dec.Decode(&x); err != nil || x != 1.0 {
168			b.Fatalf("Decode: %v after %d", err, i)
169		}
170	}
171}
172
173func BenchmarkCodeUnmarshal(b *testing.B) {
174	if codeJSON == nil {
175		b.StopTimer()
176		codeInit()
177		b.StartTimer()
178	}
179	b.RunParallel(func(pb *testing.PB) {
180		for pb.Next() {
181			var r codeResponse
182			if err := Unmarshal(codeJSON, &r); err != nil {
183				b.Fatal("Unmarshal:", err)
184			}
185		}
186	})
187	b.SetBytes(int64(len(codeJSON)))
188}
189
190func BenchmarkCodeUnmarshalReuse(b *testing.B) {
191	if codeJSON == nil {
192		b.StopTimer()
193		codeInit()
194		b.StartTimer()
195	}
196	b.RunParallel(func(pb *testing.PB) {
197		var r codeResponse
198		for pb.Next() {
199			if err := Unmarshal(codeJSON, &r); err != nil {
200				b.Fatal("Unmarshal:", err)
201			}
202		}
203	})
204	// TODO(bcmills): Is there a missing b.SetBytes here?
205}
206
207func BenchmarkUnmarshalString(b *testing.B) {
208	data := []byte(`"hello, world"`)
209	b.RunParallel(func(pb *testing.PB) {
210		var s string
211		for pb.Next() {
212			if err := Unmarshal(data, &s); err != nil {
213				b.Fatal("Unmarshal:", err)
214			}
215		}
216	})
217}
218
219func BenchmarkUnmarshalFloat64(b *testing.B) {
220	data := []byte(`3.14`)
221	b.RunParallel(func(pb *testing.PB) {
222		var f float64
223		for pb.Next() {
224			if err := Unmarshal(data, &f); err != nil {
225				b.Fatal("Unmarshal:", err)
226			}
227		}
228	})
229}
230
231func BenchmarkUnmarshalInt64(b *testing.B) {
232	data := []byte(`3`)
233	b.RunParallel(func(pb *testing.PB) {
234		var x int64
235		for pb.Next() {
236			if err := Unmarshal(data, &x); err != nil {
237				b.Fatal("Unmarshal:", err)
238			}
239		}
240	})
241}
242
243func BenchmarkIssue10335(b *testing.B) {
244	b.ReportAllocs()
245	j := []byte(`{"a":{ }}`)
246	b.RunParallel(func(pb *testing.PB) {
247		var s struct{}
248		for pb.Next() {
249			if err := Unmarshal(j, &s); err != nil {
250				b.Fatal(err)
251			}
252		}
253	})
254}
255
256func BenchmarkUnmapped(b *testing.B) {
257	b.ReportAllocs()
258	j := []byte(`{"s": "hello", "y": 2, "o": {"x": 0}, "a": [1, 99, {"x": 1}]}`)
259	b.RunParallel(func(pb *testing.PB) {
260		var s struct{}
261		for pb.Next() {
262			if err := Unmarshal(j, &s); err != nil {
263				b.Fatal(err)
264			}
265		}
266	})
267}
268