Skip to content

Commit

Permalink
perf: improve validate mesg sec/op delta by -72% (#59)
Browse files Browse the repository at this point in the history
  • Loading branch information
muktihari authored Dec 21, 2023
1 parent f7323e8 commit cdf8183
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 24 deletions.
30 changes: 6 additions & 24 deletions encoder/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,12 @@ type messageValidator struct {
func (v *messageValidator) Validate(mesg *proto.Message) error {
mesg.Header = proto.MesgNormalHeaderMask // reset default

fields := make([]proto.Field, 0, v.size(mesg.Fields))
for i := range mesg.Fields {
for i := 0; i < len(mesg.Fields); i++ {
field := &mesg.Fields[i]

if field.FieldBase == nil || field.IsExpandedField {
mesg.Fields = append(mesg.Fields[:i], mesg.Fields[i+1:]...)
i--
continue
}

Expand All @@ -93,6 +94,8 @@ func (v *messageValidator) Validate(mesg *proto.Message) error {
}

if v.options.omitInvalidValues && !hasValidValue(field.Value) {
mesg.Fields = append(mesg.Fields[:i], mesg.Fields[i+1:]...)
i--
continue
}

Expand All @@ -112,16 +115,12 @@ func (v *messageValidator) Validate(mesg *proto.Message) error {
"type '%T' is not align with the expected type '%s' for fieldIndex: %d, fieldNum: %d, fieldName: %q, fieldValue: '%v': %w",
field.Value, field.Type, i, field.Num, field.Name, field.Value, ErrValueTypeMismatch)
}

fields = append(fields, *field)
}

if len(fields) == 0 && len(mesg.DeveloperFields) == 0 {
if len(mesg.Fields) == 0 && len(mesg.DeveloperFields) == 0 {
return ErrNoFields
}

mesg.Fields = fields

switch mesg.Num {
case mesgnum.DeveloperDataId:
v.developerDataIds = append(v.developerDataIds, mesgdef.NewDeveloperDataId(mesg))
Expand Down Expand Up @@ -165,23 +164,6 @@ func (v *messageValidator) Validate(mesg *proto.Message) error {
return nil
}

// size return the size of valid fields.
// This is method ensure we just do 1 alloc on creating new slice of fields.
func (v *messageValidator) size(fields []proto.Field) byte {
var size byte
for i := range fields {
field := &fields[i]
if field.FieldBase == nil || field.IsExpandedField {
continue
}
if v.options.omitInvalidValues && !hasValidValue(field.Value) {
continue
}
size++
}
return size
}

// isValueTypeAligned checks whether the value is aligned with type. The value should be a concrete type not pointer to a value.
func isValueTypeAligned(value any, baseType basetype.BaseType) bool {
if value == nil {
Expand Down
32 changes: 32 additions & 0 deletions encoder/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,3 +430,35 @@ func BenchmarkIsValueTypeAligned(b *testing.B) {
}
})
}

func BenchmarkValidate(b *testing.B) {
b.StopTimer()
mesgValidator := NewMessageValidator()
mesg := factory.CreateMesgOnly(mesgnum.Record).WithFields(
factory.CreateField(mesgnum.Record, fieldnum.RecordSpeed).WithValue(uint16(1000)),
factory.CreateField(mesgnum.Record, fieldnum.RecordAltitude).WithValue(uint16(10000)),
func() proto.Field {
field := factory.CreateField(mesgnum.Record, fieldnum.RecordEnhancedSpeed)
field.IsExpandedField = true
field.Value = uint32(1000)
return field
}(),
func() proto.Field {
field := factory.CreateField(mesgnum.Record, fieldnum.RecordEnhancedSpeed)
field.IsExpandedField = true
field.Value = uint32(1000)
return field
}(),
func() proto.Field {
field := factory.CreateField(mesgnum.Record, fieldnum.RecordEnhancedSpeed)
field.IsExpandedField = true
field.Value = uint32(1000)
return field
}(),
)
b.StartTimer()

for i := 0; i < b.N; i++ {
_ = mesgValidator.Validate(&mesg)
}
}

0 comments on commit cdf8183

Please sign in to comment.