github.com/c9s/go@v0.0.0-20180120015821-984e81f64e0c/src/encoding/gob/timing_test.go (about) 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 }