...

Source file src/runtime/pprof/protomem.go

Documentation: runtime/pprof

		 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.
		 4  
		 5  package pprof
		 6  
		 7  import (
		 8  	"io"
		 9  	"math"
		10  	"runtime"
		11  	"strings"
		12  )
		13  
		14  // writeHeapProto writes the current heap profile in protobuf format to w.
		15  func writeHeapProto(w io.Writer, p []runtime.MemProfileRecord, rate int64, defaultSampleType string) 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")
		23  	if defaultSampleType != "" {
		24  		b.pb.int64Opt(tagProfile_DefaultSampleType, b.stringIndex(defaultSampleType))
		25  	}
		26  
		27  	values := []int64{0, 0, 0, 0}
		28  	var locs []uint64
		29  	for _, r := range p {
		30  		hideRuntime := true
		31  		for tries := 0; tries < 2; tries++ {
		32  			stk := r.Stack()
		33  			// For heap profiles, all stack
		34  			// addresses are return PCs, which is
		35  			// what appendLocsForStack expects.
		36  			if hideRuntime {
		37  				for i, addr := range stk {
		38  					if f := runtime.FuncForPC(addr); f != nil && strings.HasPrefix(f.Name(), "runtime.") {
		39  						continue
		40  					}
		41  					// Found non-runtime. Show any runtime uses above it.
		42  					stk = stk[i:]
		43  					break
		44  				}
		45  			}
		46  			locs = b.appendLocsForStack(locs[:0], stk)
		47  			if len(locs) > 0 {
		48  				break
		49  			}
		50  			hideRuntime = false // try again, and show all frames next time.
		51  		}
		52  
		53  		values[0], values[1] = scaleHeapSample(r.AllocObjects, r.AllocBytes, rate)
		54  		values[2], values[3] = scaleHeapSample(r.InUseObjects(), r.InUseBytes(), rate)
		55  		var blockSize int64
		56  		if r.AllocObjects > 0 {
		57  			blockSize = r.AllocBytes / r.AllocObjects
		58  		}
		59  		b.pbSample(values, locs, func() {
		60  			if blockSize != 0 {
		61  				b.pbLabel(tagSample_Label, "bytes", "", blockSize)
		62  			}
		63  		})
		64  	}
		65  	b.build()
		66  	return nil
		67  }
		68  
		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 {
		80  		return 0, 0
		81  	}
		82  
		83  	if rate <= 1 {
		84  		// if rate==1 all samples were collected so no adjustment is needed.
		85  		// if rate<1 treat as unknown and skip scaling.
		86  		return count, size
		87  	}
		88  
		89  	avgSize := float64(size) / float64(count)
		90  	scale := 1 / (1 - math.Exp(-avgSize/float64(rate)))
		91  
		92  	return int64(float64(count) * scale), int64(float64(size) * scale)
		93  }
		94  

View as plain text