]> Cypherpunks repositories - gostls13.git/commitdiff
internal/profile: optimize Parse allocs
authorMaxim Merzhanov <maksimmerzh@gmail.com>
Sun, 2 Nov 2025 11:28:31 +0000 (11:28 +0000)
committert hepudds <thepudds1460@gmail.com>
Mon, 3 Nov 2025 17:56:37 +0000 (09:56 -0800)
In our case, it greatly improves the performance of continuously collecting diff profiles from the net/http/pprof endpoint, such as /debug/pprof/allocs?seconds=30.

This CL is a cherry-pick of my PR upstream: https://github.com/google/pprof/pull/951

Benchmark of profile Parse func:

goos: linux
goarch: amd64
pkg: github.com/google/pprof/profile
cpu: 13th Gen Intel(R) Core(TM) i7-1360P
         │ old-parse.txt │            new-parse.txt             │
         │    sec/op     │    sec/op     vs base                │
Parse-16    62.07m ± 13%   55.54m ± 13%  -10.52% (p=0.035 n=10)

         │ old-parse.txt │            new-parse.txt             │
         │     B/op      │     B/op      vs base                │
Parse-16    47.56Mi ± 0%   41.09Mi ± 0%  -13.59% (p=0.000 n=10)

         │ old-parse.txt │            new-parse.txt            │
         │   allocs/op   │  allocs/op   vs base                │
Parse-16     272.9k ± 0%   175.8k ± 0%  -35.58% (p=0.000 n=10)

Change-Id: I737ff9b9f815fdc56bc3b5743403717c4b6f07fd
GitHub-Last-Rev: a09108f7ff7e6a27509f300d617e7adb36a9eb8a
GitHub-Pull-Request: golang/go#76145
Reviewed-on: https://go-review.googlesource.com/c/go/+/717081
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Florian Lehner <lehner.florian86@gmail.com>
src/internal/profile/proto.go

index 58ff0ad2e07789e2d2e118e3a273104c723c465d..ad6f621f883c7d6b75ff652786cbd3fd60f66158 100644 (file)
@@ -24,6 +24,7 @@ package profile
 import (
        "errors"
        "fmt"
+       "slices"
 )
 
 type buffer struct {
@@ -175,6 +176,16 @@ func le32(p []byte) uint32 {
        return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
 }
 
+func peekNumVarints(data []byte) (numVarints int) {
+       for ; len(data) > 0; numVarints++ {
+               var err error
+               if _, data, err = decodeVarint(data); err != nil {
+                       break
+               }
+       }
+       return numVarints
+}
+
 func decodeVarint(data []byte) (uint64, []byte, error) {
        var i int
        var u uint64
@@ -275,6 +286,9 @@ func decodeInt64(b *buffer, x *int64) error {
 func decodeInt64s(b *buffer, x *[]int64) error {
        if b.typ == 2 {
                // Packed encoding
+               dataLen := peekNumVarints(b.data)
+               *x = slices.Grow(*x, dataLen)
+
                data := b.data
                for len(data) > 0 {
                        var u uint64
@@ -305,8 +319,11 @@ func decodeUint64(b *buffer, x *uint64) error {
 
 func decodeUint64s(b *buffer, x *[]uint64) error {
        if b.typ == 2 {
-               data := b.data
                // Packed encoding
+               dataLen := peekNumVarints(b.data)
+               *x = slices.Grow(*x, dataLen)
+
+               data := b.data
                for len(data) > 0 {
                        var u uint64
                        var err error