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	enc := NewEncoder(ioutil.Discard)
86	for i := 0; i < b.N; i++ {
87		if err := enc.Encode(&codeStruct); err != nil {
88			b.Fatal("Encode:", err)
89		}
90	}
91	b.SetBytes(int64(len(codeJSON)))
92}
93
94func BenchmarkCodeMarshal(b *testing.B) {
95	if codeJSON == nil {
96		b.StopTimer()
97		codeInit()
98		b.StartTimer()
99	}
100	for i := 0; i < b.N; i++ {
101		if _, err := Marshal(&codeStruct); err != nil {
102			b.Fatal("Marshal:", err)
103		}
104	}
105	b.SetBytes(int64(len(codeJSON)))
106}
107
108func BenchmarkCodeDecoder(b *testing.B) {
109	if codeJSON == nil {
110		b.StopTimer()
111		codeInit()
112		b.StartTimer()
113	}
114	var buf bytes.Buffer
115	dec := NewDecoder(&buf)
116	var r codeResponse
117	for i := 0; i < b.N; i++ {
118		buf.Write(codeJSON)
119		// hide EOF
120		buf.WriteByte('\n')
121		buf.WriteByte('\n')
122		buf.WriteByte('\n')
123		if err := dec.Decode(&r); err != nil {
124			b.Fatal("Decode:", err)
125		}
126	}
127	b.SetBytes(int64(len(codeJSON)))
128}
129
130func BenchmarkDecoderStream(b *testing.B) {
131	b.StopTimer()
132	var buf bytes.Buffer
133	dec := NewDecoder(&buf)
134	buf.WriteString(`"` + strings.Repeat("x", 1000000) + `"` + "\n\n\n")
135	var x interface{}
136	if err := dec.Decode(&x); err != nil {
137		b.Fatal("Decode:", err)
138	}
139	ones := strings.Repeat(" 1\n", 300000) + "\n\n\n"
140	b.StartTimer()
141	for i := 0; i < b.N; i++ {
142		if i%300000 == 0 {
143			buf.WriteString(ones)
144		}
145		x = nil
146		if err := dec.Decode(&x); err != nil || x != 1.0 {
147			b.Fatalf("Decode: %v after %d", err, i)
148		}
149	}
150}
151
152func BenchmarkCodeUnmarshal(b *testing.B) {
153	if codeJSON == nil {
154		b.StopTimer()
155		codeInit()
156		b.StartTimer()
157	}
158	for i := 0; i < b.N; i++ {
159		var r codeResponse
160		if err := Unmarshal(codeJSON, &r); err != nil {
161			b.Fatal("Unmarshal:", err)
162		}
163	}
164	b.SetBytes(int64(len(codeJSON)))
165}
166
167func BenchmarkCodeUnmarshalReuse(b *testing.B) {
168	if codeJSON == nil {
169		b.StopTimer()
170		codeInit()
171		b.StartTimer()
172	}
173	var r codeResponse
174	for i := 0; i < b.N; i++ {
175		if err := Unmarshal(codeJSON, &r); err != nil {
176			b.Fatal("Unmarshal:", err)
177		}
178	}
179}
180
181func BenchmarkUnmarshalString(b *testing.B) {
182	data := []byte(`"hello, world"`)
183	var s string
184
185	for i := 0; i < b.N; i++ {
186		if err := Unmarshal(data, &s); err != nil {
187			b.Fatal("Unmarshal:", err)
188		}
189	}
190}
191
192func BenchmarkUnmarshalFloat64(b *testing.B) {
193	var f float64
194	data := []byte(`3.14`)
195
196	for i := 0; i < b.N; i++ {
197		if err := Unmarshal(data, &f); err != nil {
198			b.Fatal("Unmarshal:", err)
199		}
200	}
201}
202
203func BenchmarkUnmarshalInt64(b *testing.B) {
204	var x int64
205	data := []byte(`3`)
206
207	for i := 0; i < b.N; i++ {
208		if err := Unmarshal(data, &x); err != nil {
209			b.Fatal("Unmarshal:", err)
210		}
211	}
212}
213
214func BenchmarkIssue10335(b *testing.B) {
215	b.ReportAllocs()
216	var s struct{}
217	j := []byte(`{"a":{ }}`)
218	for n := 0; n < b.N; n++ {
219		if err := Unmarshal(j, &s); err != nil {
220			b.Fatal(err)
221		}
222	}
223}
224