blob: 424b7e6ea8e7a2b91dd3f105f7bb39cc9ceaaf16 [file] [log] [blame]
Rob Pike0463bd62011-03-15 17:14:02 -07001// 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
5package gob
6
7import (
8 "bytes"
Rob Pike0463bd62011-03-15 17:14:02 -07009 "io"
10 "os"
Albert Strasheim0a71a5b2013-03-06 15:52:32 -080011 "runtime"
Rob Pike0463bd62011-03-15 17:14:02 -070012 "testing"
13)
14
15type Bench struct {
16 A int
17 B float64
18 C string
19 D []byte
20}
21
Dmitriy Vyukovf7832df2014-08-08 12:48:34 +040022func benchmarkEndToEnd(b *testing.B, ctor func() interface{}, pipe func() (r io.Reader, w io.Writer, err error)) {
Dmitriy Vyukovcc063592014-08-07 21:39:32 +040023 b.RunParallel(func(pb *testing.PB) {
24 r, w, err := pipe()
25 if err != nil {
26 b.Fatal("can't get pipe:", err)
Rob Pike0463bd62011-03-15 17:14:02 -070027 }
Dmitriy Vyukovf7832df2014-08-08 12:48:34 +040028 v := ctor()
Dmitriy Vyukovcc063592014-08-07 21:39:32 +040029 enc := NewEncoder(w)
30 dec := NewDecoder(r)
31 for pb.Next() {
32 if err := enc.Encode(v); err != nil {
33 b.Fatal("encode error:", err)
34 }
35 if err := dec.Decode(v); err != nil {
36 b.Fatal("decode error:", err)
37 }
Rob Pike0463bd62011-03-15 17:14:02 -070038 }
Dmitriy Vyukovcc063592014-08-07 21:39:32 +040039 })
Rob Pike0463bd62011-03-15 17:14:02 -070040}
41
42func BenchmarkEndToEndPipe(b *testing.B) {
Dmitriy Vyukovf7832df2014-08-08 12:48:34 +040043 benchmarkEndToEnd(b, func() interface{} {
44 return &Bench{7, 3.2, "now is the time", bytes.Repeat([]byte("for all good men"), 100)}
45 }, func() (r io.Reader, w io.Writer, err error) {
Dmitriy Vyukovcc063592014-08-07 21:39:32 +040046 r, w, err = os.Pipe()
47 return
48 })
Rob Pike0463bd62011-03-15 17:14:02 -070049}
50
51func BenchmarkEndToEndByteBuffer(b *testing.B) {
Dmitriy Vyukovf7832df2014-08-08 12:48:34 +040052 benchmarkEndToEnd(b, func() interface{} {
53 return &Bench{7, 3.2, "now is the time", bytes.Repeat([]byte("for all good men"), 100)}
54 }, func() (r io.Reader, w io.Writer, err error) {
Dmitriy Vyukovcc063592014-08-07 21:39:32 +040055 var buf bytes.Buffer
56 return &buf, &buf, nil
57 })
58}
59
60func BenchmarkEndToEndSliceByteBuffer(b *testing.B) {
Dmitriy Vyukovf7832df2014-08-08 12:48:34 +040061 benchmarkEndToEnd(b, func() interface{} {
62 v := &Bench{7, 3.2, "now is the time", nil}
63 Register(v)
64 arr := make([]interface{}, 100)
65 for i := range arr {
66 arr[i] = v
67 }
68 return &arr
69 }, func() (r io.Reader, w io.Writer, err error) {
Dmitriy Vyukovcc063592014-08-07 21:39:32 +040070 var buf bytes.Buffer
71 return &buf, &buf, nil
72 })
Rob Pike0463bd62011-03-15 17:14:02 -070073}
74
75func TestCountEncodeMallocs(t *testing.T) {
Rob Pikef5787262013-08-21 14:00:45 +100076 if testing.Short() {
77 t.Skip("skipping malloc count in short mode")
78 }
Albert Strasheim0a71a5b2013-03-06 15:52:32 -080079 if runtime.GOMAXPROCS(0) > 1 {
80 t.Skip("skipping; GOMAXPROCS>1")
81 }
82
Kyle Lemons9bfd3c32013-02-02 22:52:29 -050083 const N = 1000
84
Rob Pike0463bd62011-03-15 17:14:02 -070085 var buf bytes.Buffer
86 enc := NewEncoder(&buf)
87 bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
Kyle Lemons9bfd3c32013-02-02 22:52:29 -050088
89 allocs := testing.AllocsPerRun(N, func() {
Rob Pike0463bd62011-03-15 17:14:02 -070090 err := enc.Encode(bench)
91 if err != nil {
92 t.Fatal("encode:", err)
93 }
Kyle Lemons9bfd3c32013-02-02 22:52:29 -050094 })
Rob Pikef5787262013-08-21 14:00:45 +100095 if allocs != 0 {
96 t.Fatalf("mallocs per encode of type Bench: %v; wanted 0\n", allocs)
97 }
Rob Pike0463bd62011-03-15 17:14:02 -070098}
99
100func TestCountDecodeMallocs(t *testing.T) {
Rob Pikef5787262013-08-21 14:00:45 +1000101 if testing.Short() {
102 t.Skip("skipping malloc count in short mode")
103 }
Albert Strasheim0a71a5b2013-03-06 15:52:32 -0800104 if runtime.GOMAXPROCS(0) > 1 {
105 t.Skip("skipping; GOMAXPROCS>1")
106 }
107
Kyle Lemons9bfd3c32013-02-02 22:52:29 -0500108 const N = 1000
109
Rob Pike0463bd62011-03-15 17:14:02 -0700110 var buf bytes.Buffer
111 enc := NewEncoder(&buf)
112 bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
Kyle Lemons9bfd3c32013-02-02 22:52:29 -0500113
114 // Fill the buffer with enough to decode
115 testing.AllocsPerRun(N, func() {
Rob Pike0463bd62011-03-15 17:14:02 -0700116 err := enc.Encode(bench)
117 if err != nil {
118 t.Fatal("encode:", err)
119 }
Kyle Lemons9bfd3c32013-02-02 22:52:29 -0500120 })
121
Rob Pike0463bd62011-03-15 17:14:02 -0700122 dec := NewDecoder(&buf)
Kyle Lemons9bfd3c32013-02-02 22:52:29 -0500123 allocs := testing.AllocsPerRun(N, func() {
Rob Pike0463bd62011-03-15 17:14:02 -0700124 *bench = Bench{}
125 err := dec.Decode(&bench)
126 if err != nil {
127 t.Fatal("decode:", err)
128 }
Kyle Lemons9bfd3c32013-02-02 22:52:29 -0500129 })
Aliaksandr Valialkina48de742015-08-15 13:04:46 +0300130 if allocs != 3 {
131 t.Fatalf("mallocs per decode of type Bench: %v; wanted 3\n", allocs)
Rob Pikef5787262013-08-21 14:00:45 +1000132 }
Rob Pike0463bd62011-03-15 17:14:02 -0700133}
Rob Pike5e713062014-10-17 09:00:07 -0700134
Rob Pike9965e402014-10-17 12:37:41 -0700135func BenchmarkEncodeComplex128Slice(b *testing.B) {
Rob Pike5e713062014-10-17 09:00:07 -0700136 var buf bytes.Buffer
137 enc := NewEncoder(&buf)
138 a := make([]complex128, 1000)
139 for i := range a {
140 a[i] = 1.2 + 3.4i
141 }
Rob Pike9965e402014-10-17 12:37:41 -0700142 b.ResetTimer()
Rob Pike5e713062014-10-17 09:00:07 -0700143 for i := 0; i < b.N; i++ {
144 buf.Reset()
145 err := enc.Encode(a)
146 if err != nil {
147 b.Fatal(err)
148 }
149 }
150}
151
Rob Pike9965e402014-10-17 12:37:41 -0700152func BenchmarkEncodeFloat64Slice(b *testing.B) {
Rob Pike5e713062014-10-17 09:00:07 -0700153 var buf bytes.Buffer
154 enc := NewEncoder(&buf)
155 a := make([]float64, 1000)
156 for i := range a {
157 a[i] = 1.23e4
158 }
Rob Pike9965e402014-10-17 12:37:41 -0700159 b.ResetTimer()
Rob Pike5e713062014-10-17 09:00:07 -0700160 for i := 0; i < b.N; i++ {
161 buf.Reset()
162 err := enc.Encode(a)
163 if err != nil {
164 b.Fatal(err)
165 }
166 }
167}
168
Rob Pike9965e402014-10-17 12:37:41 -0700169func BenchmarkEncodeInt32Slice(b *testing.B) {
170 var buf bytes.Buffer
171 enc := NewEncoder(&buf)
172 a := make([]int32, 1000)
173 for i := range a {
174 a[i] = 1234
175 }
176 b.ResetTimer()
177 for i := 0; i < b.N; i++ {
178 buf.Reset()
179 err := enc.Encode(a)
180 if err != nil {
181 b.Fatal(err)
182 }
183 }
184}
185
186func BenchmarkEncodeStringSlice(b *testing.B) {
Rob Pike5e713062014-10-17 09:00:07 -0700187 var buf bytes.Buffer
188 enc := NewEncoder(&buf)
189 a := make([]string, 1000)
190 for i := range a {
191 a[i] = "now is the time"
192 }
Rob Pike9965e402014-10-17 12:37:41 -0700193 b.ResetTimer()
Rob Pike5e713062014-10-17 09:00:07 -0700194 for i := 0; i < b.N; i++ {
195 buf.Reset()
196 err := enc.Encode(a)
197 if err != nil {
198 b.Fatal(err)
199 }
200 }
201}
Rob Pike9965e402014-10-17 12:37:41 -0700202
Aliaksandr Valialkina48de742015-08-15 13:04:46 +0300203func BenchmarkEncodeInterfaceSlice(b *testing.B) {
204 var buf bytes.Buffer
205 enc := NewEncoder(&buf)
206 a := make([]interface{}, 1000)
207 for i := range a {
208 a[i] = "now is the time"
209 }
210 b.ResetTimer()
211 for i := 0; i < b.N; i++ {
212 buf.Reset()
213 err := enc.Encode(a)
214 if err != nil {
215 b.Fatal(err)
216 }
217 }
218}
219
Rob Pike9965e402014-10-17 12:37:41 -0700220// benchmarkBuf is a read buffer we can reset
221type benchmarkBuf struct {
222 offset int
223 data []byte
224}
225
226func (b *benchmarkBuf) Read(p []byte) (n int, err error) {
227 n = copy(p, b.data[b.offset:])
228 if n == 0 {
229 return 0, io.EOF
230 }
231 b.offset += n
232 return
233}
234
235func (b *benchmarkBuf) ReadByte() (c byte, err error) {
236 if b.offset >= len(b.data) {
237 return 0, io.EOF
238 }
239 c = b.data[b.offset]
240 b.offset++
241 return
242}
243
244func (b *benchmarkBuf) reset() {
245 b.offset = 0
246}
247
248func BenchmarkDecodeComplex128Slice(b *testing.B) {
249 var buf bytes.Buffer
250 enc := NewEncoder(&buf)
251 a := make([]complex128, 1000)
252 for i := range a {
253 a[i] = 1.2 + 3.4i
254 }
255 err := enc.Encode(a)
256 if err != nil {
257 b.Fatal(err)
258 }
259 x := make([]complex128, 1000)
260 bbuf := benchmarkBuf{data: buf.Bytes()}
261 b.ResetTimer()
262 for i := 0; i < b.N; i++ {
263 bbuf.reset()
264 dec := NewDecoder(&bbuf)
265 err := dec.Decode(&x)
266 if err != nil {
267 b.Fatal(i, err)
268 }
269 }
270}
271
272func BenchmarkDecodeFloat64Slice(b *testing.B) {
273 var buf bytes.Buffer
274 enc := NewEncoder(&buf)
275 a := make([]float64, 1000)
276 for i := range a {
277 a[i] = 1.23e4
278 }
279 err := enc.Encode(a)
280 if err != nil {
281 b.Fatal(err)
282 }
283 x := make([]float64, 1000)
284 bbuf := benchmarkBuf{data: buf.Bytes()}
285 b.ResetTimer()
286 for i := 0; i < b.N; i++ {
287 bbuf.reset()
288 dec := NewDecoder(&bbuf)
289 err := dec.Decode(&x)
290 if err != nil {
291 b.Fatal(i, err)
292 }
293 }
294}
295
296func BenchmarkDecodeInt32Slice(b *testing.B) {
297 var buf bytes.Buffer
298 enc := NewEncoder(&buf)
299 a := make([]int32, 1000)
300 for i := range a {
301 a[i] = 1234
302 }
303 err := enc.Encode(a)
304 if err != nil {
305 b.Fatal(err)
306 }
307 x := make([]int32, 1000)
308 bbuf := benchmarkBuf{data: buf.Bytes()}
309 b.ResetTimer()
310 for i := 0; i < b.N; i++ {
311 bbuf.reset()
312 dec := NewDecoder(&bbuf)
313 err := dec.Decode(&x)
314 if err != nil {
315 b.Fatal(i, err)
316 }
317 }
318}
319
320func BenchmarkDecodeStringSlice(b *testing.B) {
321 var buf bytes.Buffer
322 enc := NewEncoder(&buf)
323 a := make([]string, 1000)
324 for i := range a {
325 a[i] = "now is the time"
326 }
327 err := enc.Encode(a)
328 if err != nil {
329 b.Fatal(err)
330 }
331 x := make([]string, 1000)
332 bbuf := benchmarkBuf{data: buf.Bytes()}
333 b.ResetTimer()
334 for i := 0; i < b.N; i++ {
335 bbuf.reset()
336 dec := NewDecoder(&bbuf)
337 err := dec.Decode(&x)
338 if err != nil {
339 b.Fatal(i, err)
340 }
341 }
342}
Aliaksandr Valialkina48de742015-08-15 13:04:46 +0300343
344func BenchmarkDecodeInterfaceSlice(b *testing.B) {
345 var buf bytes.Buffer
346 enc := NewEncoder(&buf)
347 a := make([]interface{}, 1000)
348 for i := range a {
349 a[i] = "now is the time"
350 }
351 err := enc.Encode(a)
352 if err != nil {
353 b.Fatal(err)
354 }
355 x := make([]interface{}, 1000)
356 bbuf := benchmarkBuf{data: buf.Bytes()}
357 b.ResetTimer()
358 for i := 0; i < b.N; i++ {
359 bbuf.reset()
360 dec := NewDecoder(&bbuf)
361 err := dec.Decode(&x)
362 if err != nil {
363 b.Fatal(i, err)
364 }
365 }
366}