internal/profile: optimize Parse allocs

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: a09108f7ff
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>
This commit is contained in:
Maxim Merzhanov 2025-11-02 11:28:31 +00:00 committed by t hepudds
parent 5132158ac2
commit c5559344ac

View 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