Skip to content

reflect: large performance regression in reflect.New #16161

Closed
@rhysh

Description

@rhysh

Please answer these questions before submitting your issue. Thanks!

  1. What version of Go are you using (go version)?

go1.7beta2: go version devel +fca9fc5 Thu Jun 16 19:45:33 2016 +0000 linux/amd64

  1. What operating system and processor architecture are you using (go env)?

linux/amd64

  1. What did you do?

I have a program that spends most of its time marshaling and unmarshaling data that's json- and protobuf-encoded. It's been running on go1.6.x for several months (currently go1.6.2), and I upgraded it to go1.7beta2.

It's a closed-source project, and I don't currently have a small reproducer.

  1. What did you expect to see?

I expected no major performance regressions.

  1. What did you see instead?

The program is significantly slower, with many more cycles spent in calls to reflect.New. Over 1/3rd of the program's execution time is spent in calls to reflect.(*rtype).ptrTo, which didn't even show up on profiles of the program under go1.6.2. Most of the time with ptrTo on the stack is in calls to RLock and RUnlock a *sync.RWMutex. The ptrTo cache appears to have been removed in February in 30f93f0.

Here's a bit of a go1.6.2 profile:

(pprof) peek reflect.New
126.07s of 138.79s total (90.84%)
Dropped 526 nodes (cum <= 0.69s)
----------------------------------------------------------+-------------
      flat  flat%   sum%        cum   cum%   calls calls% + context          
----------------------------------------------------------+-------------
                                             2.38s 54.71% |   redacted.path/vendor/github.com/golang/protobuf/proto.(*Buffer).dec_struct_message
                                             1.97s 45.29% |   redacted.path/vendor/github.com/golang/protobuf/proto.(*Buffer).dec_slice_struct
     0.33s  0.24%  0.24%      4.35s  3.13%                | reflect.New
                                             3.90s   100% |   reflect.unsafe_New
----------------------------------------------------------+-------------

And here's a bit of the profile with go1.7beta2:

(pprof) peek reflect.New
184.09s of 197.76s total (93.09%)
Dropped 587 nodes (cum <= 0.99s)
----------------------------------------------------------+-------------
      flat  flat%   sum%        cum   cum%   calls calls% + context          
----------------------------------------------------------+-------------
                                            39.29s 51.75% |   redacted.path/vendor/github.com/golang/protobuf/proto.(*Buffer).dec_struct_message
                                            36.64s 48.25% |   redacted.path/vendor/github.com/golang/protobuf/proto.(*Buffer).dec_slice_struct
     0.35s  0.18%  0.18%     75.93s 38.40%                | reflect.New
                                            67.65s 89.57% |   reflect.(*rtype).ptrTo
                                             7.88s 10.43% |   reflect.unsafe_New
----------------------------------------------------------+-------------
(pprof) peek ptrTo
184.09s of 197.76s total (93.09%)
Dropped 587 nodes (cum <= 0.99s)
----------------------------------------------------------+-------------
      flat  flat%   sum%        cum   cum%   calls calls% + context          
----------------------------------------------------------+-------------
                                            67.65s   100% |   reflect.New
     4.87s  2.46%  2.46%     67.65s 34.21%                | reflect.(*rtype).ptrTo
                                            37.70s 60.06% |   sync.(*RWMutex).RLock
                                            23.76s 37.85% |   sync.(*RWMutex).RUnlock
                                             1.31s  2.09% |   runtime.mapaccess1_fast64
----------------------------------------------------------+-------------

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions