1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
14 // writeHeapProto writes the current heap profile in protobuf format to w.
15 func writeHeapProto(w io
.Writer
, p
[]runtime
.MemProfileRecord
, rate
int64) error
{
16 b
:= newProfileBuilder(w
)
17 b
.pbValueType(tagProfile_PeriodType
, "space", "bytes")
18 b
.pb
.int64Opt(tagProfile_Period
, rate
)
19 b
.pbValueType(tagProfile_SampleType
, "alloc_objects", "count")
20 b
.pbValueType(tagProfile_SampleType
, "alloc_space", "bytes")
21 b
.pbValueType(tagProfile_SampleType
, "inuse_objects", "count")
22 b
.pbValueType(tagProfile_SampleType
, "inuse_space", "bytes")
24 values
:= []int64{0, 0, 0, 0}
29 for tries
:= 0; tries
< 2; tries
++ {
30 for _
, addr
:= range r
.Stack() {
31 // For heap profiles, all stack
32 // addresses are return PCs, which is
33 // what locForPC expects.
35 if f
:= runtime
.FuncForPC(addr
); f
!= nil && strings
.HasPrefix(f
.Name(), "runtime.") {
38 // Found non-runtime. Show any runtime uses above it.
42 if l
== 0 { // runtime.goexit
45 locs
= append(locs
, l
)
50 hideRuntime
= false // try again, and show all frames
53 values
[0], values
[1] = scaleHeapSample(r
.AllocObjects
, r
.AllocBytes
, rate
)
54 values
[2], values
[3] = scaleHeapSample(r
.InUseObjects(), r
.InUseBytes(), rate
)
57 blockSize
= values
[1] / values
[0]
59 b
.pbSample(values
, locs
, func() {
61 b
.pbLabel(tagSample_Label
, "bytes", "", blockSize
)
69 // scaleHeapSample adjusts the data from a heap Sample to
70 // account for its probability of appearing in the collected
71 // data. heap profiles are a sampling of the memory allocations
72 // requests in a program. We estimate the unsampled value by dividing
73 // each collected sample by its probability of appearing in the
74 // profile. heap profiles rely on a poisson process to determine
75 // which samples to collect, based on the desired average collection
76 // rate R. The probability of a sample of size S to appear in that
77 // profile is 1-exp(-S/R).
78 func scaleHeapSample(count
, size
, rate
int64) (int64, int64) {
79 if count
== 0 || size
== 0 {
84 // if rate==1 all samples were collected so no adjustment is needed.
85 // if rate<1 treat as unknown and skip scaling.
89 avgSize
:= float64(size
) / float64(count
)
90 scale
:= 1 / (1 - math
.Exp(-avgSize
/float64(rate
)))
92 return int64(float64(count
) * scale
), int64(float64(size
) * scale
)