Source file src/encoding/gob/timing_test.go

     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() any, 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() any {
    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() any {
    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() any {
    63  		v := &Bench{7, 3.2, "now is the time", nil}
    64  		Register(v)
    65  		arr := make([]any, 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 any) {
   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([]any, 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 any) {
   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  func BenchmarkDecodeStringsSlice(b *testing.B) {
   283  	a := make([][]string, 1000)
   284  	for i := range a {
   285  		a[i] = []string{"now is the time"}
   286  	}
   287  	benchmarkDecodeSlice(b, a)
   288  }
   289  func BenchmarkDecodeBytesSlice(b *testing.B) {
   290  	a := make([][]byte, 1000)
   291  	for i := range a {
   292  		a[i] = []byte("now is the time")
   293  	}
   294  	benchmarkDecodeSlice(b, a)
   295  }
   296  
   297  func BenchmarkDecodeInterfaceSlice(b *testing.B) {
   298  	a := make([]any, 1000)
   299  	for i := range a {
   300  		a[i] = "now is the time"
   301  	}
   302  	benchmarkDecodeSlice(b, a)
   303  }
   304  
   305  func BenchmarkDecodeMap(b *testing.B) {
   306  	count := 1000
   307  	m := make(map[int]int, count)
   308  	for i := 0; i < count; i++ {
   309  		m[i] = i
   310  	}
   311  	var buf bytes.Buffer
   312  	enc := NewEncoder(&buf)
   313  	err := enc.Encode(m)
   314  	if err != nil {
   315  		b.Fatal(err)
   316  	}
   317  	bbuf := benchmarkBuf{data: buf.Bytes()}
   318  	b.ResetTimer()
   319  	for i := 0; i < b.N; i++ {
   320  		var rm map[int]int
   321  		bbuf.reset()
   322  		dec := NewDecoder(&bbuf)
   323  		err := dec.Decode(&rm)
   324  		if err != nil {
   325  			b.Fatal(i, err)
   326  		}
   327  	}
   328  }
   329  

View as plain text