Home | History | Annotate | Download | only in gob
      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 package gob
      6 
      7 import (
      8 	"bytes"
      9 	"io"
     10 	"os"
     11 	"reflect"
     12 	"runtime"
     13 	"testing"
     14 )
     15 
     16 type Bench struct {
     17 	A int
     18 	B float64
     19 	C string
     20 	D []byte
     21 }
     22 
     23 func benchmarkEndToEnd(b *testing.B, ctor func() interface{}, pipe func() (r io.Reader, w io.Writer, err error)) {
     24 	b.RunParallel(func(pb *testing.PB) {
     25 		r, w, err := pipe()
     26 		if err != nil {
     27 			b.Fatal("can't get pipe:", err)
     28 		}
     29 		v := ctor()
     30 		enc := NewEncoder(w)
     31 		dec := NewDecoder(r)
     32 		for pb.Next() {
     33 			if err := enc.Encode(v); err != nil {
     34 				b.Fatal("encode error:", err)
     35 			}
     36 			if err := dec.Decode(v); err != nil {
     37 				b.Fatal("decode error:", err)
     38 			}
     39 		}
     40 	})
     41 }
     42 
     43 func BenchmarkEndToEndPipe(b *testing.B) {
     44 	benchmarkEndToEnd(b, func() interface{} {
     45 		return &Bench{7, 3.2, "now is the time", bytes.Repeat([]byte("for all good men"), 100)}
     46 	}, func() (r io.Reader, w io.Writer, err error) {
     47 		r, w, err = os.Pipe()
     48 		return
     49 	})
     50 }
     51 
     52 func BenchmarkEndToEndByteBuffer(b *testing.B) {
     53 	benchmarkEndToEnd(b, func() interface{} {
     54 		return &Bench{7, 3.2, "now is the time", bytes.Repeat([]byte("for all good men"), 100)}
     55 	}, func() (r io.Reader, w io.Writer, err error) {
     56 		var buf bytes.Buffer
     57 		return &buf, &buf, nil
     58 	})
     59 }
     60 
     61 func BenchmarkEndToEndSliceByteBuffer(b *testing.B) {
     62 	benchmarkEndToEnd(b, func() interface{} {
     63 		v := &Bench{7, 3.2, "now is the time", nil}
     64 		Register(v)
     65 		arr := make([]interface{}, 100)
     66 		for i := range arr {
     67 			arr[i] = v
     68 		}
     69 		return &arr
     70 	}, func() (r io.Reader, w io.Writer, err error) {
     71 		var buf bytes.Buffer
     72 		return &buf, &buf, nil
     73 	})
     74 }
     75 
     76 func TestCountEncodeMallocs(t *testing.T) {
     77 	if testing.Short() {
     78 		t.Skip("skipping malloc count in short mode")
     79 	}
     80 	if runtime.GOMAXPROCS(0) > 1 {
     81 		t.Skip("skipping; GOMAXPROCS>1")
     82 	}
     83 
     84 	const N = 1000
     85 
     86 	var buf bytes.Buffer
     87 	enc := NewEncoder(&buf)
     88 	bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
     89 
     90 	allocs := testing.AllocsPerRun(N, func() {
     91 		err := enc.Encode(bench)
     92 		if err != nil {
     93 			t.Fatal("encode:", err)
     94 		}
     95 	})
     96 	if allocs != 0 {
     97 		t.Fatalf("mallocs per encode of type Bench: %v; wanted 0\n", allocs)
     98 	}
     99 }
    100 
    101 func TestCountDecodeMallocs(t *testing.T) {
    102 	if testing.Short() {
    103 		t.Skip("skipping malloc count in short mode")
    104 	}
    105 	if runtime.GOMAXPROCS(0) > 1 {
    106 		t.Skip("skipping; GOMAXPROCS>1")
    107 	}
    108 
    109 	const N = 1000
    110 
    111 	var buf bytes.Buffer
    112 	enc := NewEncoder(&buf)
    113 	bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
    114 
    115 	// Fill the buffer with enough to decode
    116 	testing.AllocsPerRun(N, func() {
    117 		err := enc.Encode(bench)
    118 		if err != nil {
    119 			t.Fatal("encode:", err)
    120 		}
    121 	})
    122 
    123 	dec := NewDecoder(&buf)
    124 	allocs := testing.AllocsPerRun(N, func() {
    125 		*bench = Bench{}
    126 		err := dec.Decode(&bench)
    127 		if err != nil {
    128 			t.Fatal("decode:", err)
    129 		}
    130 	})
    131 	if allocs != 3 {
    132 		t.Fatalf("mallocs per decode of type Bench: %v; wanted 3\n", allocs)
    133 	}
    134 }
    135 
    136 func benchmarkEncodeSlice(b *testing.B, a interface{}) {
    137 	b.ResetTimer()
    138 	b.RunParallel(func(pb *testing.PB) {
    139 		var buf bytes.Buffer
    140 		enc := NewEncoder(&buf)
    141 
    142 		for pb.Next() {
    143 			buf.Reset()
    144 			err := enc.Encode(a)
    145 			if err != nil {
    146 				b.Fatal(err)
    147 			}
    148 		}
    149 	})
    150 }
    151 
    152 func BenchmarkEncodeComplex128Slice(b *testing.B) {
    153 	a := make([]complex128, 1000)
    154 	for i := range a {
    155 		a[i] = 1.2 + 3.4i
    156 	}
    157 	benchmarkEncodeSlice(b, a)
    158 }
    159 
    160 func BenchmarkEncodeFloat64Slice(b *testing.B) {
    161 	a := make([]float64, 1000)
    162 	for i := range a {
    163 		a[i] = 1.23e4
    164 	}
    165 	benchmarkEncodeSlice(b, a)
    166 }
    167 
    168 func BenchmarkEncodeInt32Slice(b *testing.B) {
    169 	a := make([]int32, 1000)
    170 	for i := range a {
    171 		a[i] = int32(i * 100)
    172 	}
    173 	benchmarkEncodeSlice(b, a)
    174 }
    175 
    176 func BenchmarkEncodeStringSlice(b *testing.B) {
    177 	a := make([]string, 1000)
    178 	for i := range a {
    179 		a[i] = "now is the time"
    180 	}
    181 	benchmarkEncodeSlice(b, a)
    182 }
    183 
    184 func BenchmarkEncodeInterfaceSlice(b *testing.B) {
    185 	a := make([]interface{}, 1000)
    186 	for i := range a {
    187 		a[i] = "now is the time"
    188 	}
    189 	benchmarkEncodeSlice(b, a)
    190 }
    191 
    192 // benchmarkBuf is a read buffer we can reset
    193 type benchmarkBuf struct {
    194 	offset int
    195 	data   []byte
    196 }
    197 
    198 func (b *benchmarkBuf) Read(p []byte) (n int, err error) {
    199 	n = copy(p, b.data[b.offset:])
    200 	if n == 0 {
    201 		return 0, io.EOF
    202 	}
    203 	b.offset += n
    204 	return
    205 }
    206 
    207 func (b *benchmarkBuf) ReadByte() (c byte, err error) {
    208 	if b.offset >= len(b.data) {
    209 		return 0, io.EOF
    210 	}
    211 	c = b.data[b.offset]
    212 	b.offset++
    213 	return
    214 }
    215 
    216 func (b *benchmarkBuf) reset() {
    217 	b.offset = 0
    218 }
    219 
    220 func benchmarkDecodeSlice(b *testing.B, a interface{}) {
    221 	var buf bytes.Buffer
    222 	enc := NewEncoder(&buf)
    223 	err := enc.Encode(a)
    224 	if err != nil {
    225 		b.Fatal(err)
    226 	}
    227 
    228 	ra := reflect.ValueOf(a)
    229 	rt := ra.Type()
    230 	b.ResetTimer()
    231 
    232 	b.RunParallel(func(pb *testing.PB) {
    233 		// TODO(#19025): Move per-thread allocation before ResetTimer.
    234 		rp := reflect.New(rt)
    235 		rp.Elem().Set(reflect.MakeSlice(rt, ra.Len(), ra.Cap()))
    236 		p := rp.Interface()
    237 
    238 		bbuf := benchmarkBuf{data: buf.Bytes()}
    239 
    240 		for pb.Next() {
    241 			bbuf.reset()
    242 			dec := NewDecoder(&bbuf)
    243 			err := dec.Decode(p)
    244 			if err != nil {
    245 				b.Fatal(err)
    246 			}
    247 		}
    248 	})
    249 }
    250 
    251 func BenchmarkDecodeComplex128Slice(b *testing.B) {
    252 	a := make([]complex128, 1000)
    253 	for i := range a {
    254 		a[i] = 1.2 + 3.4i
    255 	}
    256 	benchmarkDecodeSlice(b, a)
    257 }
    258 
    259 func BenchmarkDecodeFloat64Slice(b *testing.B) {
    260 	a := make([]float64, 1000)
    261 	for i := range a {
    262 		a[i] = 1.23e4
    263 	}
    264 	benchmarkDecodeSlice(b, a)
    265 }
    266 
    267 func BenchmarkDecodeInt32Slice(b *testing.B) {
    268 	a := make([]int32, 1000)
    269 	for i := range a {
    270 		a[i] = 1234
    271 	}
    272 	benchmarkDecodeSlice(b, a)
    273 }
    274 
    275 func BenchmarkDecodeStringSlice(b *testing.B) {
    276 	a := make([]string, 1000)
    277 	for i := range a {
    278 		a[i] = "now is the time"
    279 	}
    280 	benchmarkDecodeSlice(b, a)
    281 }
    282 
    283 func BenchmarkDecodeInterfaceSlice(b *testing.B) {
    284 	a := make([]interface{}, 1000)
    285 	for i := range a {
    286 		a[i] = "now is the time"
    287 	}
    288 	benchmarkDecodeSlice(b, a)
    289 }
    290 
    291 func BenchmarkDecodeMap(b *testing.B) {
    292 	count := 1000
    293 	m := make(map[int]int, count)
    294 	for i := 0; i < count; i++ {
    295 		m[i] = i
    296 	}
    297 	var buf bytes.Buffer
    298 	enc := NewEncoder(&buf)
    299 	err := enc.Encode(m)
    300 	if err != nil {
    301 		b.Fatal(err)
    302 	}
    303 	bbuf := benchmarkBuf{data: buf.Bytes()}
    304 	b.ResetTimer()
    305 	for i := 0; i < b.N; i++ {
    306 		var rm map[int]int
    307 		bbuf.reset()
    308 		dec := NewDecoder(&bbuf)
    309 		err := dec.Decode(&rm)
    310 		if err != nil {
    311 			b.Fatal(i, err)
    312 		}
    313 	}
    314 }
    315