1package msgpack_test
2
3import (
4	"bytes"
5	"io/ioutil"
6	"math"
7	"testing"
8	"time"
9
10	"github.com/vmihailenco/msgpack"
11)
12
13func BenchmarkDiscard(b *testing.B) {
14	enc := msgpack.NewEncoder(ioutil.Discard)
15
16	b.ResetTimer()
17
18	for i := 0; i < b.N; i++ {
19		if err := enc.Encode(nil); err != nil {
20			b.Fatal(err)
21		}
22		if err := enc.Encode("hello"); err != nil {
23			b.Fatal(err)
24		}
25	}
26}
27
28func benchmarkEncodeDecode(b *testing.B, src, dst interface{}) {
29	var buf bytes.Buffer
30	enc := msgpack.NewEncoder(&buf)
31	dec := msgpack.NewDecoder(&buf)
32
33	b.ResetTimer()
34
35	for i := 0; i < b.N; i++ {
36		if err := enc.Encode(src); err != nil {
37			b.Fatal(err)
38		}
39		if err := dec.Decode(dst); err != nil {
40			b.Fatal(err)
41		}
42	}
43}
44
45func BenchmarkBool(b *testing.B) {
46	var dst bool
47	benchmarkEncodeDecode(b, true, &dst)
48}
49
50func BenchmarkInt0(b *testing.B) {
51	var dst int
52	benchmarkEncodeDecode(b, 1, &dst)
53}
54
55func BenchmarkInt1(b *testing.B) {
56	var dst int
57	benchmarkEncodeDecode(b, -33, &dst)
58}
59
60func BenchmarkInt2(b *testing.B) {
61	var dst int
62	benchmarkEncodeDecode(b, 128, &dst)
63}
64
65func BenchmarkInt4(b *testing.B) {
66	var dst int
67	benchmarkEncodeDecode(b, 32768, &dst)
68}
69
70func BenchmarkInt8(b *testing.B) {
71	var dst int
72	benchmarkEncodeDecode(b, int64(2147483648), &dst)
73}
74
75func BenchmarkInt32(b *testing.B) {
76	var dst int32
77	benchmarkEncodeDecode(b, int32(0), &dst)
78}
79
80func BenchmarkTime(b *testing.B) {
81	var dst time.Time
82	benchmarkEncodeDecode(b, time.Now(), &dst)
83}
84
85func BenchmarkDuration(b *testing.B) {
86	var dst time.Duration
87	benchmarkEncodeDecode(b, time.Hour, &dst)
88}
89
90func BenchmarkByteSlice(b *testing.B) {
91	src := make([]byte, 1024)
92	var dst []byte
93	benchmarkEncodeDecode(b, src, &dst)
94}
95
96func BenchmarkByteArray(b *testing.B) {
97	var src [1024]byte
98	var dst [1024]byte
99	benchmarkEncodeDecode(b, src, &dst)
100}
101
102func BenchmarkByteArrayPtr(b *testing.B) {
103	var src [1024]byte
104	var dst [1024]byte
105	benchmarkEncodeDecode(b, &src, &dst)
106}
107
108func BenchmarkMapStringString(b *testing.B) {
109	src := map[string]string{
110		"hello": "world",
111		"foo":   "bar",
112	}
113	var dst map[string]string
114	benchmarkEncodeDecode(b, src, &dst)
115}
116
117func BenchmarkMapStringStringPtr(b *testing.B) {
118	src := map[string]string{
119		"hello": "world",
120		"foo":   "bar",
121	}
122	var dst map[string]string
123	dstptr := &dst
124	benchmarkEncodeDecode(b, src, &dstptr)
125}
126
127func BenchmarkMapStringInterface(b *testing.B) {
128	src := map[string]interface{}{
129		"hello": "world",
130		"foo":   "bar",
131	}
132	var dst map[string]interface{}
133	benchmarkEncodeDecode(b, src, &dst)
134}
135
136func BenchmarkMapIntInt(b *testing.B) {
137	src := map[int]int{
138		1: 10,
139		2: 20,
140	}
141	var dst map[int]int
142	benchmarkEncodeDecode(b, src, &dst)
143}
144
145func BenchmarkStringSlice(b *testing.B) {
146	src := []string{"hello", "world"}
147	var dst []string
148	benchmarkEncodeDecode(b, src, &dst)
149}
150
151func BenchmarkStringSlicePtr(b *testing.B) {
152	src := []string{"hello", "world"}
153	var dst []string
154	dstptr := &dst
155	benchmarkEncodeDecode(b, src, &dstptr)
156}
157
158type benchmarkStruct struct {
159	Name      string
160	Age       int
161	Colors    []string
162	Data      []byte
163	CreatedAt time.Time
164	UpdatedAt time.Time
165}
166
167type benchmarkStruct2 struct {
168	Name      string
169	Age       int
170	Colors    []string
171	Data      []byte
172	CreatedAt time.Time
173	UpdatedAt time.Time
174}
175
176var _ msgpack.CustomEncoder = (*benchmarkStruct2)(nil)
177var _ msgpack.CustomDecoder = (*benchmarkStruct2)(nil)
178
179func (s *benchmarkStruct2) EncodeMsgpack(enc *msgpack.Encoder) error {
180	return enc.EncodeMulti(
181		s.Name,
182		s.Colors,
183		s.Age,
184		s.Data,
185		s.CreatedAt,
186		s.UpdatedAt,
187	)
188}
189
190func (s *benchmarkStruct2) DecodeMsgpack(dec *msgpack.Decoder) error {
191	return dec.DecodeMulti(
192		&s.Name,
193		&s.Colors,
194		&s.Age,
195		&s.Data,
196		&s.CreatedAt,
197		&s.UpdatedAt,
198	)
199}
200
201func structForBenchmark() *benchmarkStruct {
202	return &benchmarkStruct{
203		Name:      "Hello World",
204		Colors:    []string{"red", "orange", "yellow", "green", "blue", "violet"},
205		Age:       math.MaxInt32,
206		Data:      make([]byte, 1024),
207		CreatedAt: time.Now(),
208		UpdatedAt: time.Now(),
209	}
210}
211
212func structForBenchmark2() *benchmarkStruct2 {
213	return &benchmarkStruct2{
214		Name:      "Hello World",
215		Colors:    []string{"red", "orange", "yellow", "green", "blue", "violet"},
216		Age:       math.MaxInt32,
217		Data:      make([]byte, 1024),
218		CreatedAt: time.Now(),
219		UpdatedAt: time.Now(),
220	}
221}
222
223func BenchmarkStructVmihailencoMsgpack(b *testing.B) {
224	in := structForBenchmark()
225	out := new(benchmarkStruct)
226
227	b.ResetTimer()
228
229	for i := 0; i < b.N; i++ {
230		buf, err := msgpack.Marshal(in)
231		if err != nil {
232			b.Fatal(err)
233		}
234
235		err = msgpack.Unmarshal(buf, out)
236		if err != nil {
237			b.Fatal(err)
238		}
239	}
240}
241
242func BenchmarkStructMarshal(b *testing.B) {
243	in := structForBenchmark()
244
245	b.ResetTimer()
246
247	for i := 0; i < b.N; i++ {
248		_, err := msgpack.Marshal(in)
249		if err != nil {
250			b.Fatal(err)
251		}
252	}
253}
254
255func BenchmarkStructUnmarshal(b *testing.B) {
256	in := structForBenchmark()
257	buf, err := msgpack.Marshal(in)
258	if err != nil {
259		b.Fatal(err)
260	}
261	out := new(benchmarkStruct)
262
263	b.ResetTimer()
264
265	for i := 0; i < b.N; i++ {
266		err = msgpack.Unmarshal(buf, out)
267		if err != nil {
268			b.Fatal(err)
269		}
270	}
271}
272
273func BenchmarkStructManual(b *testing.B) {
274	in := structForBenchmark2()
275	out := new(benchmarkStruct2)
276
277	b.ResetTimer()
278
279	for i := 0; i < b.N; i++ {
280		buf, err := msgpack.Marshal(in)
281		if err != nil {
282			b.Fatal(err)
283		}
284
285		err = msgpack.Unmarshal(buf, out)
286		if err != nil {
287			b.Fatal(err)
288		}
289	}
290}
291
292type benchmarkStructPartially struct {
293	Name string
294	Age  int
295}
296
297func BenchmarkStructUnmarshalPartially(b *testing.B) {
298	in := structForBenchmark()
299	buf, err := msgpack.Marshal(in)
300	if err != nil {
301		b.Fatal(err)
302	}
303	out := new(benchmarkStructPartially)
304
305	b.ResetTimer()
306
307	for i := 0; i < b.N; i++ {
308		err = msgpack.Unmarshal(buf, out)
309		if err != nil {
310			b.Fatal(err)
311		}
312	}
313}
314
315func BenchmarkQuery(b *testing.B) {
316	var records []map[string]interface{}
317	for i := 0; i < 1000; i++ {
318		record := map[string]interface{}{
319			"id":    i,
320			"attrs": map[string]interface{}{"phone": i},
321		}
322		records = append(records, record)
323	}
324
325	bs, err := msgpack.Marshal(records)
326	if err != nil {
327		b.Fatal(err)
328	}
329
330	dec := msgpack.NewDecoder(bytes.NewBuffer(bs))
331
332	b.ResetTimer()
333
334	for i := 0; i < b.N; i++ {
335		dec.Reset(bytes.NewBuffer(bs))
336
337		values, err := dec.Query("10.attrs.phone")
338		if err != nil {
339			b.Fatal(err)
340		}
341		if values[0].(int8) != 10 {
342			b.Fatalf("%v != %d", values[0], 10)
343		}
344	}
345}
346