Skip to content

Commit

Permalink
internal/impl: improve MessageInfo.New performance
Browse files Browse the repository at this point in the history
Calling the ProtoReflect method of the newly-constructed
message avoids an allocation in MessageInfo.MessageOf in
the common case of a generated message with an optimized
ProtoReflect method.

Benchmark for creating an empty message, darwin/arm64 M1 laptop:

    name                 old time/op    new time/op    delta
    EmptyMessage/New-10    32.1ns ± 2%    23.7ns ± 2%  -26.06%  (p=0.000 n=10+9)

    name                 old alloc/op   new alloc/op   delta
    EmptyMessage/New-10     64.0B ± 0%     48.0B ± 0%  -25.00%  (p=0.000 n=10+10)

    name                 old allocs/op  new allocs/op  delta
    EmptyMessage/New-10      2.00 ± 0%      1.00 ± 0%  -50.00%  (p=0.000 n=10+10)

Change-Id: Ifa3c3ffa8edc76f78399306d0f4964eae4aacd28
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/418677
Reviewed-by: Michael Stapelberg <stapelberg@google.com>
Reviewed-by: Lasse Folger <lassefolger@google.com>
  • Loading branch information
neild committed Jul 21, 2022
1 parent b0a9446 commit de9682a
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 1 deletion.
8 changes: 8 additions & 0 deletions internal/benchmarks/micro/micro_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ func BenchmarkEmptyMessage(b *testing.B) {
}
})
})
b.Run("New", func(b *testing.B) {
mt := (&emptypb.Empty{}).ProtoReflect().Type()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
mt.New()
}
})
})
}

// BenchmarkRepeatedInt32 tests a message containing 500 non-packed repeated int32s.
Expand Down
6 changes: 5 additions & 1 deletion internal/impl/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,11 @@ fieldLoop:
}

func (mi *MessageInfo) New() protoreflect.Message {
return mi.MessageOf(reflect.New(mi.GoReflectType.Elem()).Interface())
m := reflect.New(mi.GoReflectType.Elem()).Interface()
if r, ok := m.(protoreflect.ProtoMessage); ok {
return r.ProtoReflect()
}
return mi.MessageOf(m)
}
func (mi *MessageInfo) Zero() protoreflect.Message {
return mi.MessageOf(reflect.Zero(mi.GoReflectType).Interface())
Expand Down

0 comments on commit de9682a

Please sign in to comment.