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