1// Copyright 2013-2020 Aerospike, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package aerospike
16
17import (
18	"bytes"
19	"encoding/binary"
20	"math"
21	"math/rand"
22	"runtime"
23	"strings"
24	"testing"
25	// "time"
26
27	_ "net/http/pprof"
28)
29
30var buf *benchBuffer
31
32func init() {
33	buf = &benchBuffer{dataBuffer: make([]byte, 1024*1024), dataOffset: 0}
34}
35
36func Benchmark_Pack_binary_Write(b *testing.B) {
37	buf := new(bytes.Buffer)
38	for i := 0; i < b.N; i++ {
39		buf.Reset()
40		binary.Write(buf, binary.BigEndian, int64(0))
41	}
42}
43
44func Benchmark_Pack_binary_PutUint64(b *testing.B) {
45	buf := make([]byte, 8)
46	for i := 0; i < b.N; i++ {
47		binary.BigEndian.PutUint64(buf, 0)
48	}
49}
50
51func doPack(val interface{}, b *testing.B) {
52	var err error
53	v := NewValue(val)
54	runtime.GC()
55	b.ResetTimer()
56	for i := 0; i < b.N; i++ {
57		buf.dataOffset = 0
58		_, err = v.pack(buf)
59		if err != nil {
60			panic(err)
61		}
62	}
63}
64
65func Benchmark_Pack_________Int64(b *testing.B) {
66	val := rand.Int63()
67	doPack(val, b)
68}
69
70func Benchmark_Pack_________Int32(b *testing.B) {
71	val := rand.Int31()
72	doPack(val, b)
73}
74
75func Benchmark_Pack_String______1(b *testing.B) {
76	val := strings.Repeat("s", 1)
77	doPack(val, b)
78}
79
80func Benchmark_Pack_String_____10(b *testing.B) {
81	val := strings.Repeat("s", 10)
82	doPack(val, b)
83}
84
85func Benchmark_Pack_String____100(b *testing.B) {
86	val := strings.Repeat("s", 100)
87	doPack(val, b)
88}
89
90func Benchmark_Pack_String___1000(b *testing.B) {
91	val := strings.Repeat("s", 1000)
92	doPack(val, b)
93}
94
95func Benchmark_Pack_String__10000(b *testing.B) {
96	val := strings.Repeat("s", 10000)
97	doPack(val, b)
98}
99
100func Benchmark_Pack_String_100000(b *testing.B) {
101	val := strings.Repeat("s", 100000)
102	doPack(val, b)
103}
104
105func Benchmark_Pack_Complex_IfcArray_Direct(b *testing.B) {
106	val := []interface{}{1, 1, 1, "a simple string", nil, rand.Int63(), []byte{12, 198, 211}}
107	doPack(val, b)
108}
109
110var _ ListIter = myList([]string{})
111
112// supports old generic slices
113type myList []string
114
115func (cs myList) PackList(buf BufferEx) (int, error) {
116	size := 0
117	for _, elem := range cs {
118		n, err := packString(buf, elem)
119		size += n
120		if err != nil {
121			return size, err
122		}
123	}
124	return size, nil
125}
126
127func (m myList) Len() int {
128	return len(m)
129}
130
131func Benchmark_Pack_Complex_Array_ListIter(b *testing.B) {
132	val := myList([]string{strings.Repeat("s", 1), strings.Repeat("s", 2), strings.Repeat("s", 3), strings.Repeat("s", 4), strings.Repeat("s", 5), strings.Repeat("s", 6), strings.Repeat("s", 7), strings.Repeat("s", 8), strings.Repeat("s", 9), strings.Repeat("s", 10)})
133	doPack(val, b)
134}
135
136func Benchmark_Pack_Complex_ValueArray(b *testing.B) {
137	val := []Value{NewValue(1), NewValue(strings.Repeat("s", 100000)), NewValue(1.75), NewValue(nil)}
138	doPack(val, b)
139}
140
141func Benchmark_Pack_Complex_Map(b *testing.B) {
142	val := map[interface{}]interface{}{
143		rand.Int63(): rand.Int63(),
144		nil:          1,
145		"s":          491871,
146		15892987:     strings.Repeat("s", 100),
147		"s2":         []interface{}{"a simple string", nil, rand.Int63(), []byte{12, 198, 211}},
148	}
149	doPack(val, b)
150}
151
152func Benchmark_Pack_Complex_JsonMap(b *testing.B) {
153	val := map[string]interface{}{
154		"rand.Int63()": rand.Int63(),
155		"nil":          1,
156		"s":            491871,
157		"15892987":     strings.Repeat("s", 100),
158		"s2":           []interface{}{"a simple string", nil, rand.Int63(), []byte{12, 198, 211}},
159	}
160	doPack(val, b)
161}
162
163////////////////////////////////////////////////////////////////////////////////////////
164type benchBuffer struct {
165	dataBuffer []byte
166	dataOffset int
167}
168
169// Int64ToBytes converts an int64 into slice of Bytes.
170func (bb *benchBuffer) WriteInt64(num int64) (int, error) {
171	return bb.WriteUint64(uint64(num))
172}
173
174// Uint64ToBytes converts an uint64 into slice of Bytes.
175func (bb *benchBuffer) WriteUint64(num uint64) (int, error) {
176	binary.BigEndian.PutUint64(bb.dataBuffer[bb.dataOffset:bb.dataOffset+8], num)
177	bb.dataOffset += 8
178	return 8, nil
179}
180
181// Int32ToBytes converts an int32 to a byte slice of size 4
182func (bb *benchBuffer) WriteInt32(num int32) (int, error) {
183	return bb.WriteUint32(uint32(num))
184}
185
186// Uint32ToBytes converts an uint32 to a byte slice of size 4
187func (bb *benchBuffer) WriteUint32(num uint32) (int, error) {
188	binary.BigEndian.PutUint32(bb.dataBuffer[bb.dataOffset:bb.dataOffset+4], num)
189	bb.dataOffset += 4
190	return 4, nil
191}
192
193// Int16ToBytes converts an int16 to slice of bytes
194func (bb *benchBuffer) WriteInt16(num int16) (int, error) {
195	return bb.WriteUint16(uint16(num))
196}
197
198// Int16ToBytes converts an int16 to slice of bytes
199func (bb *benchBuffer) WriteUint16(num uint16) (int, error) {
200	binary.BigEndian.PutUint16(bb.dataBuffer[bb.dataOffset:bb.dataOffset+2], num)
201	bb.dataOffset += 2
202	return 2, nil
203}
204
205func (bb *benchBuffer) WriteFloat32(float float32) (int, error) {
206	bits := math.Float32bits(float)
207	binary.BigEndian.PutUint32(bb.dataBuffer[bb.dataOffset:bb.dataOffset+4], bits)
208	bb.dataOffset += 4
209	return 4, nil
210}
211
212func (bb *benchBuffer) WriteFloat64(float float64) (int, error) {
213	bits := math.Float64bits(float)
214	binary.BigEndian.PutUint64(bb.dataBuffer[bb.dataOffset:bb.dataOffset+8], bits)
215	bb.dataOffset += 8
216	return 8, nil
217}
218
219func (bb *benchBuffer) WriteByte(b byte) error {
220	bb.dataBuffer[bb.dataOffset] = b
221	bb.dataOffset++
222	return nil
223}
224
225func (bb *benchBuffer) WriteString(s string) (int, error) {
226	copy(bb.dataBuffer[bb.dataOffset:bb.dataOffset+len(s)], s)
227	bb.dataOffset += len(s)
228	return len(s), nil
229}
230
231func (bb *benchBuffer) Write(b []byte) (int, error) {
232	copy(bb.dataBuffer[bb.dataOffset:bb.dataOffset+len(b)], b)
233	bb.dataOffset += len(b)
234	return len(b), nil
235}
236