Skip to content

Commit

Permalink
perf: improve proto marshaler (#60)
Browse files Browse the repository at this point in the history
  • Loading branch information
muktihari authored Dec 21, 2023
1 parent cdf8183 commit fc7ab4a
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 23 deletions.
37 changes: 23 additions & 14 deletions proto/marshaler.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"encoding"
"encoding/binary"
"fmt"
"sync"

"github.com/muktihari/fit/kit/byteorder"
"github.com/muktihari/fit/profile/typedef"
Expand All @@ -19,8 +20,6 @@ import (
var (
_ encoding.BinaryMarshaler = &FileHeader{}
_ encoding.BinaryMarshaler = &MessageDefinition{}
_ encoding.BinaryMarshaler = &FieldDefinition{}
_ encoding.BinaryMarshaler = &DeveloperFieldDefinition{}
_ encoding.BinaryMarshaler = &Message{}
)

Expand Down Expand Up @@ -65,8 +64,11 @@ func (m *MessageDefinition) MarshalBinary() ([]byte, error) {
b = append(b, byte(len(m.FieldDefinitions)))

for i := range m.FieldDefinitions {
bs, _ := m.FieldDefinitions[i].MarshalBinary()
b = append(b, bs...)
b = append(b,
m.FieldDefinitions[i].Num,
m.FieldDefinitions[i].Size,
byte(m.FieldDefinitions[i].BaseType),
)
}

if (m.Header & DevDataMask) != DevDataMask {
Expand All @@ -75,29 +77,33 @@ func (m *MessageDefinition) MarshalBinary() ([]byte, error) {

b = append(b, byte(len(m.DeveloperFieldDefinitions)))
for i := range m.DeveloperFieldDefinitions {
bs, _ := m.DeveloperFieldDefinitions[i].MarshalBinary()
b = append(b, bs...)
b = append(b,
m.DeveloperFieldDefinitions[i].Num,
m.DeveloperFieldDefinitions[i].Size,
m.DeveloperFieldDefinitions[i].DeveloperDataIndex,
)
}

return b, nil
}

func (f *FieldDefinition) MarshalBinary() ([]byte, error) {
return []byte{f.Num, f.Size, byte(f.BaseType)}, nil
}

func (f *DeveloperFieldDefinition) MarshalBinary() ([]byte, error) {
return []byte{f.Num, f.Size, f.DeveloperDataIndex}, nil
var bufPool = sync.Pool{
New: func() any {
return new(bytes.Buffer)
},
}

func (m *Message) MarshalBinary() ([]byte, error) {
buf := new(bytes.Buffer)
buf := bufPool.Get().(*bytes.Buffer)
buf.Reset()

buf.WriteByte(m.Header)

for i := range m.Fields {
field := &m.Fields[i]
b, err := typedef.Marshal(field.Value, byteorder.Select(m.Architecture))
if err != nil {
bufPool.Put(buf)
return nil, fmt.Errorf("field: [num: %d, value: %v]: %w", field.Num, field.Value, err)
}
buf.Write(b)
Expand All @@ -107,10 +113,13 @@ func (m *Message) MarshalBinary() ([]byte, error) {
developerField := &m.DeveloperFields[i]
b, err := typedef.Marshal(developerField.Value, byteorder.Select(m.Architecture))
if err != nil {
bufPool.Put(buf)
return nil, fmt.Errorf("developer field: [num: %d, value: %v]: %w", developerField.Num, developerField.Value, err)
}
buf.Write(b)
}

return buf.Bytes(), nil
b := buf.Bytes()
bufPool.Put(buf)
return b, nil
}
37 changes: 28 additions & 9 deletions proto/marshaler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ import (
"testing"

"github.com/google/go-cmp/cmp"
"github.com/muktihari/fit/factory"
"github.com/muktihari/fit/profile/basetype"
"github.com/muktihari/fit/profile/typedef"
"github.com/muktihari/fit/profile/untyped/fieldnum"
"github.com/muktihari/fit/profile/untyped/mesgnum"
"github.com/muktihari/fit/proto"
)

Expand Down Expand Up @@ -135,15 +138,6 @@ func TestMessageDefinitionMarshaler(t *testing.T) {
}
}

func TestDeveloperFieldDefinitionMarshaler(t *testing.T) {
f := proto.DeveloperFieldDefinition{Num: 0, Size: 1, DeveloperDataIndex: 0}
b, _ := f.MarshalBinary()
expected := []byte{0, 1, 0}
if diff := cmp.Diff(b, expected); diff != "" {
t.Fatal(diff)
}
}

func TestMessageMarshaler(t *testing.T) {
tt := []struct {
name string
Expand Down Expand Up @@ -241,3 +235,28 @@ func TestMessageMarshaler(t *testing.T) {
})
}
}

func BenchmarkMarshalMessageDefinition(b *testing.B) {
b.StopTimer()
mesg := factory.CreateMesg(mesgnum.Record)
mesgDef := proto.CreateMessageDefinition(&mesg)
b.StartTimer()

for i := 0; i < b.N; i++ {
_, _ = mesgDef.MarshalBinary()
}
}

func BenchmarkMarshalMessage(b *testing.B) {
b.StopTimer()
mesg := factory.CreateMesg(mesgnum.Record).WithFieldValues(map[byte]any{
fieldnum.RecordPositionLat: int32(1000),
fieldnum.RecordPositionLong: int32(1000),
fieldnum.RecordSpeed: uint16(1000),
})
b.StartTimer()

for i := 0; i < b.N; i++ {
_, _ = mesg.MarshalBinary()
}
}

0 comments on commit fc7ab4a

Please sign in to comment.