Skip to content

Commit fdd30f4

Browse files
committed
test: add benchmarks
Closes TNTP-3733
1 parent 93a7028 commit fdd30f4

File tree

9 files changed

+918
-2
lines changed

9 files changed

+918
-2
lines changed

.github/workflows/testing.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,18 @@ jobs:
5151
run: make coverage coveralls-deps coveralls
5252

5353
run-benchmarks:
54-
if: false
54+
if: (github.event_name == 'push') ||
55+
(github.event_name == 'pull_request' &&
56+
github.event.pull_request.head.repo.full_name != github.repository) ||
57+
(github.event_name == 'workflow_dispatch')
5558

5659
runs-on: ubuntu-latest
5760

61+
strategy:
62+
fail-fast: false
63+
matrix:
64+
golang: ['1.24', 'stable']
65+
5866
steps:
5967
- uses: actions/checkout@v4
6068
- uses: actions/setup-go@v5

Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ testrace:
1717
@echo "Running tests with race flag"
1818
@go test ./... -count=100 -race
1919

20+
.PHONY: bench
21+
bench:
22+
@echo "Running benchmarks"
23+
@go test ./... -count=1 -bench=. -benchmem
24+
2025
.PHONY: coverage
2126
coverage:
2227
@echo "Running tests with coveralls"

bench_ext_test.go

Lines changed: 363 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,363 @@
1+
package option_test
2+
3+
import (
4+
"bytes"
5+
"errors"
6+
"slices"
7+
"testing"
8+
9+
"github.com/tarantool/go-option"
10+
"github.com/vmihailenco/msgpack/v5"
11+
"github.com/vmihailenco/msgpack/v5/msgpcode"
12+
)
13+
14+
type BenchExt struct {
15+
data []byte
16+
}
17+
18+
func (e *BenchExt) MarshalMsgpack() ([]byte, error) {
19+
return e.data, nil
20+
}
21+
22+
func (e *BenchExt) UnmarshalMsgpack(b []byte) error {
23+
e.data = slices.Clone(b)
24+
return nil
25+
}
26+
27+
func (e *BenchExt) ExtType() int8 {
28+
return 8
29+
}
30+
31+
type Optional1BenchExt struct {
32+
value BenchExt
33+
set bool
34+
}
35+
36+
func SomeOptional1BenchExt(value BenchExt) Optional1BenchExt {
37+
return Optional1BenchExt{value: value, set: true}
38+
}
39+
40+
func NoneOptional1BenchExt() Optional1BenchExt {
41+
return Optional1BenchExt{}
42+
}
43+
44+
var (
45+
NilBytes = []byte{msgpcode.Nil}
46+
)
47+
48+
func (o Optional1BenchExt) MarshalMsgpack() ([]byte, error) {
49+
if o.set {
50+
return o.value.MarshalMsgpack()
51+
}
52+
return NilBytes, nil
53+
}
54+
55+
func (o *Optional1BenchExt) UnmarshalMsgpack(b []byte) error {
56+
if b[0] == msgpcode.Nil {
57+
o.set = false
58+
return nil
59+
}
60+
o.set = true
61+
return o.value.UnmarshalMsgpack(b)
62+
}
63+
64+
func (o Optional1BenchExt) EncodeMsgpack(enc *msgpack.Encoder) error {
65+
switch {
66+
case !o.set:
67+
return enc.EncodeNil()
68+
default:
69+
mpdata, err := o.value.MarshalMsgpack()
70+
if err != nil {
71+
return err
72+
}
73+
74+
err = enc.EncodeExtHeader(o.value.ExtType(), len(mpdata))
75+
if err != nil {
76+
return err
77+
}
78+
79+
mpdataLen, err := enc.Writer().Write(mpdata)
80+
switch {
81+
case err != nil:
82+
return err
83+
case mpdataLen != len(mpdata):
84+
return errors.New("failed to write mpdata")
85+
}
86+
87+
return nil
88+
}
89+
}
90+
91+
func (o *Optional1BenchExt) DecodeMsgpack(dec *msgpack.Decoder) error {
92+
code, err := dec.PeekCode()
93+
if err != nil {
94+
return err
95+
}
96+
97+
switch {
98+
case code == msgpcode.Nil:
99+
o.set = false
100+
case msgpcode.IsExt(code):
101+
extID, extLen, err := dec.DecodeExtHeader()
102+
switch {
103+
case err != nil:
104+
return err
105+
case extID != o.value.ExtType():
106+
return errors.New("unexpected extension type")
107+
default:
108+
ext := make([]byte, extLen)
109+
110+
err := dec.ReadFull(ext)
111+
if err != nil {
112+
return err
113+
}
114+
115+
err = o.value.UnmarshalMsgpack(ext)
116+
if err != nil {
117+
return err
118+
}
119+
}
120+
default:
121+
return errors.New("unexpected code")
122+
}
123+
return nil
124+
}
125+
126+
type Optional2BenchExt struct {
127+
value BenchExt
128+
set bool
129+
}
130+
131+
func SomeOptional2BenchExt(value BenchExt) Optional2BenchExt {
132+
return Optional2BenchExt{value: value, set: true}
133+
}
134+
135+
func NoneOptional2BenchExt() Optional2BenchExt {
136+
return Optional2BenchExt{}
137+
}
138+
139+
func (o Optional2BenchExt) MarshalMsgpack() ([]byte, error) {
140+
if o.set {
141+
return o.value.MarshalMsgpack()
142+
}
143+
return NilBytes, nil
144+
}
145+
146+
func (o *Optional2BenchExt) UnmarshalMsgpack(b []byte) error {
147+
if b[0] == msgpcode.Nil {
148+
o.set = false
149+
return nil
150+
}
151+
o.set = true
152+
return o.value.UnmarshalMsgpack(b)
153+
}
154+
155+
func (o Optional2BenchExt) EncodeMsgpack(enc *msgpack.Encoder) error {
156+
switch {
157+
case !o.set:
158+
return enc.EncodeNil()
159+
default:
160+
return enc.Encode(&o.value)
161+
}
162+
}
163+
164+
func (o *Optional2BenchExt) DecodeMsgpack(dec *msgpack.Decoder) error {
165+
code, err := dec.PeekCode()
166+
if err != nil {
167+
return err
168+
}
169+
170+
switch {
171+
case code == msgpcode.Nil:
172+
o.set = false
173+
return nil
174+
case msgpcode.IsExt(code):
175+
return dec.Decode(&o.value)
176+
default:
177+
return errors.New("unexpected code")
178+
}
179+
}
180+
181+
type MsgpackExtInterface interface {
182+
ExtType() int8
183+
msgpack.Marshaler
184+
msgpack.Unmarshaler
185+
}
186+
187+
type OptionalGenericStructWithInterface[T MsgpackExtInterface] struct {
188+
value T
189+
set bool
190+
}
191+
192+
func NewOptionalGenericStructWithInterface[T MsgpackExtInterface](value T) *OptionalGenericStructWithInterface[T] {
193+
return &OptionalGenericStructWithInterface[T]{
194+
value: value,
195+
set: true,
196+
}
197+
}
198+
199+
func NewEmptyOptionalGenericStructWithInterface[T MsgpackExtInterface]() *OptionalGenericStructWithInterface[T] {
200+
return &OptionalGenericStructWithInterface[T]{
201+
set: false,
202+
}
203+
}
204+
205+
func (o *OptionalGenericStructWithInterface[T]) DecodeMsgpack(d *msgpack.Decoder) error {
206+
code, err := d.PeekCode()
207+
if err != nil {
208+
return err
209+
}
210+
211+
switch {
212+
case code == msgpcode.Nil:
213+
o.set = false
214+
case msgpcode.IsExt(code):
215+
o.set = true
216+
217+
extID, extLen, err := d.DecodeExtHeader()
218+
switch {
219+
case err != nil:
220+
return err
221+
case extID != o.value.ExtType():
222+
return errors.New("unexpected extension type")
223+
default:
224+
ext := make([]byte, extLen)
225+
226+
err := d.ReadFull(ext)
227+
if err != nil {
228+
return err
229+
}
230+
231+
err = o.value.UnmarshalMsgpack(ext)
232+
if err != nil {
233+
return err
234+
}
235+
}
236+
237+
default:
238+
return errors.New("unexpected type")
239+
}
240+
241+
return nil
242+
}
243+
244+
func (o *OptionalGenericStructWithInterface[T]) EncodeMsgpack(e *msgpack.Encoder) error {
245+
switch {
246+
case !o.set:
247+
return e.EncodeNil()
248+
default:
249+
mpdata, err := o.value.MarshalMsgpack()
250+
if err != nil {
251+
return err
252+
}
253+
254+
err = e.EncodeExtHeader(o.value.ExtType(), len(mpdata))
255+
if err != nil {
256+
return err
257+
}
258+
259+
mpdataLen, err := e.Writer().Write(mpdata)
260+
switch {
261+
case err != nil:
262+
return err
263+
case mpdataLen != len(mpdata):
264+
return errors.New("failed to write mpdata")
265+
}
266+
267+
return nil
268+
}
269+
270+
}
271+
272+
func BenchmarkExtension(b *testing.B) {
273+
msgpack.RegisterExt(8, &BenchExt{})
274+
275+
var buf bytes.Buffer
276+
buf.Grow(4096)
277+
278+
enc := msgpack.GetEncoder()
279+
enc.Reset(&buf)
280+
281+
dec := msgpack.GetDecoder()
282+
dec.Reset(&buf)
283+
284+
b.Run("Optional1Bench", func(b *testing.B) {
285+
for b.Loop() {
286+
o := SomeOptional1BenchExt(BenchExt{[]byte{1, 2, 3}})
287+
288+
err := o.EncodeMsgpack(enc)
289+
if err != nil {
290+
b.Fatal(err)
291+
}
292+
293+
err = o.DecodeMsgpack(dec)
294+
if err != nil {
295+
b.Fatal(err)
296+
}
297+
}
298+
})
299+
300+
b.Run("Optional2Bench", func(b *testing.B) {
301+
for b.Loop() {
302+
o := SomeOptional2BenchExt(BenchExt{[]byte{1, 2, 3}})
303+
304+
err := o.EncodeMsgpack(enc)
305+
if err != nil {
306+
b.Fatal(err)
307+
}
308+
309+
err = o.DecodeMsgpack(dec)
310+
if err != nil {
311+
b.Fatal(err)
312+
}
313+
}
314+
})
315+
316+
b.Run("OptionalBenchGeneric", func(b *testing.B) {
317+
for b.Loop() {
318+
o := option.Some(BenchExt{[]byte{1, 2, 3}})
319+
320+
err := o.EncodeMsgpack(enc)
321+
if err != nil {
322+
b.Fatal(err)
323+
}
324+
325+
err = o.DecodeMsgpack(dec)
326+
if err != nil {
327+
b.Fatal(err)
328+
}
329+
}
330+
})
331+
332+
b.Run("OptionalGenericStructWithInterface", func(b *testing.B) {
333+
for b.Loop() {
334+
o := NewOptionalGenericStructWithInterface(&BenchExt{[]byte{1, 2, 3}})
335+
336+
err := o.EncodeMsgpack(enc)
337+
if err != nil {
338+
b.Fatal(err)
339+
}
340+
341+
err = o.DecodeMsgpack(dec)
342+
if err != nil {
343+
b.Fatal(err)
344+
}
345+
}
346+
})
347+
348+
b.Run("Default", func(b *testing.B) {
349+
for b.Loop() {
350+
o := BenchExt{[]byte{1, 2, 3}}
351+
352+
err := enc.Encode(&o)
353+
if err != nil {
354+
b.Fatal(err)
355+
}
356+
357+
err = dec.Decode(&o)
358+
if err != nil {
359+
b.Fatal(err)
360+
}
361+
}
362+
})
363+
}

0 commit comments

Comments
 (0)