diff options
| author | Nick Ripley <nick.ripley@datadoghq.com> | 2026-03-27 09:35:51 -0400 |
|---|---|---|
| committer | Nick Ripley <nick.ripley@datadoghq.com> | 2026-03-28 13:07:33 -0700 |
| commit | d247ed00e498e9717fb7c80d126bee5a8afdb4e8 (patch) | |
| tree | 07641e62bb021d5cd34a0ad0a2fc9ea30fbb9c47 /src/runtime/pprof | |
| parent | 1fd68799c39bd4a3f7e16a1ee24fcaca3efe5357 (diff) | |
| download | go-d247ed00e498e9717fb7c80d126bee5a8afdb4e8.tar.xz | |
runtime: remove redundant fields from memory profile records
The memProfCycle struct holds allocation counts and bytes allocated, and
frees and bytes freed. But the memory profile records are already
aggregated by allocation size, which is stored in the "size" field of
the bucket struct. We can derive the bytes allocated/freed using the
counts and the size we already store. Thus we can delete the bytes
fields from memProfCycle, saving 64 bytes per memRecord.
We can do something similar for the profilerecord.MemProfileRecord type.
We just need to know the object size and we can derive the allocated and
freed bytes accordingly.
Change-Id: I103885c2f29471b25283e330674fc16d6a6a6964
Reviewed-on: https://go-review.googlesource.com/c/go/+/760140
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Diffstat (limited to 'src/runtime/pprof')
| -rw-r--r-- | src/runtime/pprof/pprof.go | 6 | ||||
| -rw-r--r-- | src/runtime/pprof/protomem.go | 23 | ||||
| -rw-r--r-- | src/runtime/pprof/protomem_test.go | 6 |
3 files changed, 14 insertions, 21 deletions
diff --git a/src/runtime/pprof/pprof.go b/src/runtime/pprof/pprof.go index d560eeade1..6708d2dfa3 100644 --- a/src/runtime/pprof/pprof.go +++ b/src/runtime/pprof/pprof.go @@ -674,9 +674,9 @@ func writeHeapInternal(w io.Writer, debug int, defaultSampleType string) error { var total runtime.MemProfileRecord for i := range p { r := &p[i] - total.AllocBytes += r.AllocBytes + total.AllocBytes += r.AllocObjects * r.ObjectSize total.AllocObjects += r.AllocObjects - total.FreeBytes += r.FreeBytes + total.FreeBytes += r.FreeObjects * r.ObjectSize total.FreeObjects += r.FreeObjects } @@ -706,7 +706,7 @@ func writeHeapInternal(w io.Writer, debug int, defaultSampleType string) error { r := &p[i] fmt.Fprintf(w, "%d: %d [%d: %d] @", r.InUseObjects(), r.InUseBytes(), - r.AllocObjects, r.AllocBytes) + r.AllocObjects, r.AllocObjects*r.ObjectSize) for _, pc := range r.Stack { fmt.Fprintf(w, " %#x", pc) } diff --git a/src/runtime/pprof/protomem.go b/src/runtime/pprof/protomem.go index e0d3746e36..02847c2dda 100644 --- a/src/runtime/pprof/protomem.go +++ b/src/runtime/pprof/protomem.go @@ -51,16 +51,10 @@ func writeHeapProto(w io.Writer, p []profilerecord.MemProfileRecord, rate int64, hideRuntime = false // try again, and show all frames next time. } - values[0], values[1] = scaleHeapSample(r.AllocObjects, r.AllocBytes, rate) - values[2], values[3] = scaleHeapSample(r.InUseObjects(), r.InUseBytes(), rate) - var blockSize int64 - if r.AllocObjects > 0 { - blockSize = r.AllocBytes / r.AllocObjects - } + values[0], values[1] = scaleHeapSample(r.AllocObjects, r.ObjectSize, rate) + values[2], values[3] = scaleHeapSample(r.InUseObjects(), r.ObjectSize, rate) b.pbSample(values, locs, func() { - if blockSize != 0 { - b.pbLabel(tagSample_Label, "bytes", "", blockSize) - } + b.pbLabel(tagSample_Label, "bytes", "", r.ObjectSize) }) } return b.build() @@ -75,19 +69,18 @@ func writeHeapProto(w io.Writer, p []profilerecord.MemProfileRecord, rate int64, // which samples to collect, based on the desired average collection // rate R. The probability of a sample of size S to appear in that // profile is 1-exp(-S/R). -func scaleHeapSample(count, size, rate int64) (int64, int64) { - if count == 0 || size == 0 { +func scaleHeapSample(count, avgSize, rate int64) (int64, int64) { + if count == 0 || avgSize == 0 { return 0, 0 } if rate <= 1 { // if rate==1 all samples were collected so no adjustment is needed. // if rate<1 treat as unknown and skip scaling. - return count, size + return count, count * avgSize } - avgSize := float64(size) / float64(count) - scale := 1 / (1 - math.Exp(-avgSize/float64(rate))) + scale := 1 / (1 - math.Exp(-float64(avgSize)/float64(rate))) - return int64(float64(count) * scale), int64(float64(size) * scale) + return int64(float64(count) * scale), int64(float64(count*avgSize) * scale) } diff --git a/src/runtime/pprof/protomem_test.go b/src/runtime/pprof/protomem_test.go index 6f3231d42a..6b2254298e 100644 --- a/src/runtime/pprof/protomem_test.go +++ b/src/runtime/pprof/protomem_test.go @@ -27,9 +27,9 @@ func TestConvertMemProfile(t *testing.T) { a1, a2 := uintptr(addr1)+1, uintptr(addr2)+1 rate := int64(512 * 1024) rec := []profilerecord.MemProfileRecord{ - {AllocBytes: 4096, FreeBytes: 1024, AllocObjects: 4, FreeObjects: 1, Stack: []uintptr{a1, a2}}, - {AllocBytes: 512 * 1024, FreeBytes: 0, AllocObjects: 1, FreeObjects: 0, Stack: []uintptr{a2 + 1, a2 + 2}}, - {AllocBytes: 512 * 1024, FreeBytes: 512 * 1024, AllocObjects: 1, FreeObjects: 1, Stack: []uintptr{a1 + 1, a1 + 2, a2 + 3}}, + {ObjectSize: 1024, AllocObjects: 4, FreeObjects: 1, Stack: []uintptr{a1, a2}}, + {ObjectSize: 512 * 1024, AllocObjects: 1, FreeObjects: 0, Stack: []uintptr{a2 + 1, a2 + 2}}, + {ObjectSize: 512 * 1024, AllocObjects: 1, FreeObjects: 1, Stack: []uintptr{a1 + 1, a1 + 2, a2 + 3}}, } periodType := &profile.ValueType{Type: "space", Unit: "bytes"} |
