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 "runtime" 12 "testing" 13 ) 14 15 type Bench struct { 16 A int 17 B float64 18 C string 19 D []byte 20 } 21 22 func benchmarkEndToEnd(b *testing.B, ctor func() interface{}, pipe func() (r io.Reader, w io.Writer, err error)) { 23 b.RunParallel(func(pb *testing.PB) { 24 r, w, err := pipe() 25 if err != nil { 26 b.Fatal("can't get pipe:", err) 27 } 28 v := ctor() 29 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 } 38 } 39 }) 40 } 41 42 func BenchmarkEndToEndPipe(b *testing.B) { 43 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) { 46 r, w, err = os.Pipe() 47 return 48 }) 49 } 50 51 func BenchmarkEndToEndByteBuffer(b *testing.B) { 52 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) { 55 var buf bytes.Buffer 56 return &buf, &buf, nil 57 }) 58 } 59 60 func BenchmarkEndToEndSliceByteBuffer(b *testing.B) { 61 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) { 70 var buf bytes.Buffer 71 return &buf, &buf, nil 72 }) 73 } 74 75 func TestCountEncodeMallocs(t *testing.T) { 76 if testing.Short() { 77 t.Skip("skipping malloc count in short mode") 78 } 79 if runtime.GOMAXPROCS(0) > 1 { 80 t.Skip("skipping; GOMAXPROCS>1") 81 } 82 83 const N = 1000 84 85 var buf bytes.Buffer 86 enc := NewEncoder(&buf) 87 bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")} 88 89 allocs := testing.AllocsPerRun(N, func() { 90 err := enc.Encode(bench) 91 if err != nil { 92 t.Fatal("encode:", err) 93 } 94 }) 95 if allocs != 0 { 96 t.Fatalf("mallocs per encode of type Bench: %v; wanted 0\n", allocs) 97 } 98 } 99 100 func TestCountDecodeMallocs(t *testing.T) { 101 if testing.Short() { 102 t.Skip("skipping malloc count in short mode") 103 } 104 if runtime.GOMAXPROCS(0) > 1 { 105 t.Skip("skipping; GOMAXPROCS>1") 106 } 107 108 const N = 1000 109 110 var buf bytes.Buffer 111 enc := NewEncoder(&buf) 112 bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")} 113 114 // Fill the buffer with enough to decode 115 testing.AllocsPerRun(N, func() { 116 err := enc.Encode(bench) 117 if err != nil { 118 t.Fatal("encode:", err) 119 } 120 }) 121 122 dec := NewDecoder(&buf) 123 allocs := testing.AllocsPerRun(N, func() { 124 *bench = Bench{} 125 err := dec.Decode(&bench) 126 if err != nil { 127 t.Fatal("decode:", err) 128 } 129 }) 130 if allocs != 4 { 131 t.Fatalf("mallocs per decode of type Bench: %v; wanted 4\n", allocs) 132 } 133 } 134 135 func BenchmarkEncodeComplex128Slice(b *testing.B) { 136 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 } 142 b.ResetTimer() 143 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 152 func BenchmarkEncodeFloat64Slice(b *testing.B) { 153 var buf bytes.Buffer 154 enc := NewEncoder(&buf) 155 a := make([]float64, 1000) 156 for i := range a { 157 a[i] = 1.23e4 158 } 159 b.ResetTimer() 160 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 169 func 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 186 func BenchmarkEncodeStringSlice(b *testing.B) { 187 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 } 193 b.ResetTimer() 194 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 } 202 203 // benchmarkBuf is a read buffer we can reset 204 type benchmarkBuf struct { 205 offset int 206 data []byte 207 } 208 209 func (b *benchmarkBuf) Read(p []byte) (n int, err error) { 210 n = copy(p, b.data[b.offset:]) 211 if n == 0 { 212 return 0, io.EOF 213 } 214 b.offset += n 215 return 216 } 217 218 func (b *benchmarkBuf) ReadByte() (c byte, err error) { 219 if b.offset >= len(b.data) { 220 return 0, io.EOF 221 } 222 c = b.data[b.offset] 223 b.offset++ 224 return 225 } 226 227 func (b *benchmarkBuf) reset() { 228 b.offset = 0 229 } 230 231 func BenchmarkDecodeComplex128Slice(b *testing.B) { 232 var buf bytes.Buffer 233 enc := NewEncoder(&buf) 234 a := make([]complex128, 1000) 235 for i := range a { 236 a[i] = 1.2 + 3.4i 237 } 238 err := enc.Encode(a) 239 if err != nil { 240 b.Fatal(err) 241 } 242 x := make([]complex128, 1000) 243 bbuf := benchmarkBuf{data: buf.Bytes()} 244 b.ResetTimer() 245 for i := 0; i < b.N; i++ { 246 bbuf.reset() 247 dec := NewDecoder(&bbuf) 248 err := dec.Decode(&x) 249 if err != nil { 250 b.Fatal(i, err) 251 } 252 } 253 } 254 255 func BenchmarkDecodeFloat64Slice(b *testing.B) { 256 var buf bytes.Buffer 257 enc := NewEncoder(&buf) 258 a := make([]float64, 1000) 259 for i := range a { 260 a[i] = 1.23e4 261 } 262 err := enc.Encode(a) 263 if err != nil { 264 b.Fatal(err) 265 } 266 x := make([]float64, 1000) 267 bbuf := benchmarkBuf{data: buf.Bytes()} 268 b.ResetTimer() 269 for i := 0; i < b.N; i++ { 270 bbuf.reset() 271 dec := NewDecoder(&bbuf) 272 err := dec.Decode(&x) 273 if err != nil { 274 b.Fatal(i, err) 275 } 276 } 277 } 278 279 func BenchmarkDecodeInt32Slice(b *testing.B) { 280 var buf bytes.Buffer 281 enc := NewEncoder(&buf) 282 a := make([]int32, 1000) 283 for i := range a { 284 a[i] = 1234 285 } 286 err := enc.Encode(a) 287 if err != nil { 288 b.Fatal(err) 289 } 290 x := make([]int32, 1000) 291 bbuf := benchmarkBuf{data: buf.Bytes()} 292 b.ResetTimer() 293 for i := 0; i < b.N; i++ { 294 bbuf.reset() 295 dec := NewDecoder(&bbuf) 296 err := dec.Decode(&x) 297 if err != nil { 298 b.Fatal(i, err) 299 } 300 } 301 } 302 303 func BenchmarkDecodeStringSlice(b *testing.B) { 304 var buf bytes.Buffer 305 enc := NewEncoder(&buf) 306 a := make([]string, 1000) 307 for i := range a { 308 a[i] = "now is the time" 309 } 310 err := enc.Encode(a) 311 if err != nil { 312 b.Fatal(err) 313 } 314 x := make([]string, 1000) 315 bbuf := benchmarkBuf{data: buf.Bytes()} 316 b.ResetTimer() 317 for i := 0; i < b.N; i++ { 318 bbuf.reset() 319 dec := NewDecoder(&bbuf) 320 err := dec.Decode(&x) 321 if err != nil { 322 b.Fatal(i, err) 323 } 324 } 325 } 326