...
Run Format

Source file src/encoding/gob/timing_test.go

Documentation: encoding/gob

  // Copyright 2011 The Go Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style
  // license that can be found in the LICENSE file.
  
  package gob
  
  import (
  	"bytes"
  	"io"
  	"os"
  	"reflect"
  	"runtime"
  	"testing"
  )
  
  type Bench struct {
  	A int
  	B float64
  	C string
  	D []byte
  }
  
  func benchmarkEndToEnd(b *testing.B, ctor func() interface{}, pipe func() (r io.Reader, w io.Writer, err error)) {
  	b.RunParallel(func(pb *testing.PB) {
  		r, w, err := pipe()
  		if err != nil {
  			b.Fatal("can't get pipe:", err)
  		}
  		v := ctor()
  		enc := NewEncoder(w)
  		dec := NewDecoder(r)
  		for pb.Next() {
  			if err := enc.Encode(v); err != nil {
  				b.Fatal("encode error:", err)
  			}
  			if err := dec.Decode(v); err != nil {
  				b.Fatal("decode error:", err)
  			}
  		}
  	})
  }
  
  func BenchmarkEndToEndPipe(b *testing.B) {
  	benchmarkEndToEnd(b, func() interface{} {
  		return &Bench{7, 3.2, "now is the time", bytes.Repeat([]byte("for all good men"), 100)}
  	}, func() (r io.Reader, w io.Writer, err error) {
  		r, w, err = os.Pipe()
  		return
  	})
  }
  
  func BenchmarkEndToEndByteBuffer(b *testing.B) {
  	benchmarkEndToEnd(b, func() interface{} {
  		return &Bench{7, 3.2, "now is the time", bytes.Repeat([]byte("for all good men"), 100)}
  	}, func() (r io.Reader, w io.Writer, err error) {
  		var buf bytes.Buffer
  		return &buf, &buf, nil
  	})
  }
  
  func BenchmarkEndToEndSliceByteBuffer(b *testing.B) {
  	benchmarkEndToEnd(b, func() interface{} {
  		v := &Bench{7, 3.2, "now is the time", nil}
  		Register(v)
  		arr := make([]interface{}, 100)
  		for i := range arr {
  			arr[i] = v
  		}
  		return &arr
  	}, func() (r io.Reader, w io.Writer, err error) {
  		var buf bytes.Buffer
  		return &buf, &buf, nil
  	})
  }
  
  func TestCountEncodeMallocs(t *testing.T) {
  	if testing.Short() {
  		t.Skip("skipping malloc count in short mode")
  	}
  	if runtime.GOMAXPROCS(0) > 1 {
  		t.Skip("skipping; GOMAXPROCS>1")
  	}
  
  	const N = 1000
  
  	var buf bytes.Buffer
  	enc := NewEncoder(&buf)
  	bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
  
  	allocs := testing.AllocsPerRun(N, func() {
  		err := enc.Encode(bench)
  		if err != nil {
  			t.Fatal("encode:", err)
  		}
  	})
  	if allocs != 0 {
  		t.Fatalf("mallocs per encode of type Bench: %v; wanted 0\n", allocs)
  	}
  }
  
  func TestCountDecodeMallocs(t *testing.T) {
  	if testing.Short() {
  		t.Skip("skipping malloc count in short mode")
  	}
  	if runtime.GOMAXPROCS(0) > 1 {
  		t.Skip("skipping; GOMAXPROCS>1")
  	}
  
  	const N = 1000
  
  	var buf bytes.Buffer
  	enc := NewEncoder(&buf)
  	bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")}
  
  	// Fill the buffer with enough to decode
  	testing.AllocsPerRun(N, func() {
  		err := enc.Encode(bench)
  		if err != nil {
  			t.Fatal("encode:", err)
  		}
  	})
  
  	dec := NewDecoder(&buf)
  	allocs := testing.AllocsPerRun(N, func() {
  		*bench = Bench{}
  		err := dec.Decode(&bench)
  		if err != nil {
  			t.Fatal("decode:", err)
  		}
  	})
  	if allocs != 3 {
  		t.Fatalf("mallocs per decode of type Bench: %v; wanted 3\n", allocs)
  	}
  }
  
  func benchmarkEncodeSlice(b *testing.B, a interface{}) {
  	b.ResetTimer()
  	b.RunParallel(func(pb *testing.PB) {
  		var buf bytes.Buffer
  		enc := NewEncoder(&buf)
  
  		for pb.Next() {
  			buf.Reset()
  			err := enc.Encode(a)
  			if err != nil {
  				b.Fatal(err)
  			}
  		}
  	})
  }
  
  func BenchmarkEncodeComplex128Slice(b *testing.B) {
  	a := make([]complex128, 1000)
  	for i := range a {
  		a[i] = 1.2 + 3.4i
  	}
  	benchmarkEncodeSlice(b, a)
  }
  
  func BenchmarkEncodeFloat64Slice(b *testing.B) {
  	a := make([]float64, 1000)
  	for i := range a {
  		a[i] = 1.23e4
  	}
  	benchmarkEncodeSlice(b, a)
  }
  
  func BenchmarkEncodeInt32Slice(b *testing.B) {
  	a := make([]int32, 1000)
  	for i := range a {
  		a[i] = int32(i * 100)
  	}
  	benchmarkEncodeSlice(b, a)
  }
  
  func BenchmarkEncodeStringSlice(b *testing.B) {
  	a := make([]string, 1000)
  	for i := range a {
  		a[i] = "now is the time"
  	}
  	benchmarkEncodeSlice(b, a)
  }
  
  func BenchmarkEncodeInterfaceSlice(b *testing.B) {
  	a := make([]interface{}, 1000)
  	for i := range a {
  		a[i] = "now is the time"
  	}
  	benchmarkEncodeSlice(b, a)
  }
  
  // benchmarkBuf is a read buffer we can reset
  type benchmarkBuf struct {
  	offset int
  	data   []byte
  }
  
  func (b *benchmarkBuf) Read(p []byte) (n int, err error) {
  	n = copy(p, b.data[b.offset:])
  	if n == 0 {
  		return 0, io.EOF
  	}
  	b.offset += n
  	return
  }
  
  func (b *benchmarkBuf) ReadByte() (c byte, err error) {
  	if b.offset >= len(b.data) {
  		return 0, io.EOF
  	}
  	c = b.data[b.offset]
  	b.offset++
  	return
  }
  
  func (b *benchmarkBuf) reset() {
  	b.offset = 0
  }
  
  func benchmarkDecodeSlice(b *testing.B, a interface{}) {
  	var buf bytes.Buffer
  	enc := NewEncoder(&buf)
  	err := enc.Encode(a)
  	if err != nil {
  		b.Fatal(err)
  	}
  
  	ra := reflect.ValueOf(a)
  	rt := ra.Type()
  	b.ResetTimer()
  
  	b.RunParallel(func(pb *testing.PB) {
  		// TODO(#19025): Move per-thread allocation before ResetTimer.
  		rp := reflect.New(rt)
  		rp.Elem().Set(reflect.MakeSlice(rt, ra.Len(), ra.Cap()))
  		p := rp.Interface()
  
  		bbuf := benchmarkBuf{data: buf.Bytes()}
  
  		for pb.Next() {
  			bbuf.reset()
  			dec := NewDecoder(&bbuf)
  			err := dec.Decode(p)
  			if err != nil {
  				b.Fatal(err)
  			}
  		}
  	})
  }
  
  func BenchmarkDecodeComplex128Slice(b *testing.B) {
  	a := make([]complex128, 1000)
  	for i := range a {
  		a[i] = 1.2 + 3.4i
  	}
  	benchmarkDecodeSlice(b, a)
  }
  
  func BenchmarkDecodeFloat64Slice(b *testing.B) {
  	a := make([]float64, 1000)
  	for i := range a {
  		a[i] = 1.23e4
  	}
  	benchmarkDecodeSlice(b, a)
  }
  
  func BenchmarkDecodeInt32Slice(b *testing.B) {
  	a := make([]int32, 1000)
  	for i := range a {
  		a[i] = 1234
  	}
  	benchmarkDecodeSlice(b, a)
  }
  
  func BenchmarkDecodeStringSlice(b *testing.B) {
  	a := make([]string, 1000)
  	for i := range a {
  		a[i] = "now is the time"
  	}
  	benchmarkDecodeSlice(b, a)
  }
  
  func BenchmarkDecodeInterfaceSlice(b *testing.B) {
  	a := make([]interface{}, 1000)
  	for i := range a {
  		a[i] = "now is the time"
  	}
  	benchmarkDecodeSlice(b, a)
  }
  
  func BenchmarkDecodeMap(b *testing.B) {
  	count := 1000
  	m := make(map[int]int, count)
  	for i := 0; i < count; i++ {
  		m[i] = i
  	}
  	var buf bytes.Buffer
  	enc := NewEncoder(&buf)
  	err := enc.Encode(m)
  	if err != nil {
  		b.Fatal(err)
  	}
  	bbuf := benchmarkBuf{data: buf.Bytes()}
  	b.ResetTimer()
  	for i := 0; i < b.N; i++ {
  		var rm map[int]int
  		bbuf.reset()
  		dec := NewDecoder(&bbuf)
  		err := dec.Decode(&rm)
  		if err != nil {
  			b.Fatal(i, err)
  		}
  	}
  }
  

View as plain text