...
Run Format

Source file src/runtime/pprof/protomem.go

Documentation: runtime/pprof

  // Copyright 2016 The Go Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style
  // license that can be found in the LICENSE file.
  
  package pprof
  
  import (
  	"io"
  	"math"
  	"runtime"
  	"strings"
  )
  
  // writeHeapProto writes the current heap profile in protobuf format to w.
  func writeHeapProto(w io.Writer, p []runtime.MemProfileRecord, rate int64) error {
  	b := newProfileBuilder(w)
  	b.pbValueType(tagProfile_PeriodType, "space", "bytes")
  	b.pb.int64Opt(tagProfile_Period, rate)
  	b.pbValueType(tagProfile_SampleType, "alloc_objects", "count")
  	b.pbValueType(tagProfile_SampleType, "alloc_space", "bytes")
  	b.pbValueType(tagProfile_SampleType, "inuse_objects", "count")
  	b.pbValueType(tagProfile_SampleType, "inuse_space", "bytes")
  
  	values := []int64{0, 0, 0, 0}
  	var locs []uint64
  	for _, r := range p {
  		locs = locs[:0]
  		hideRuntime := true
  		for tries := 0; tries < 2; tries++ {
  			for _, addr := range r.Stack() {
  				// For heap profiles, all stack
  				// addresses are return PCs, which is
  				// what locForPC expects.
  				if hideRuntime {
  					if f := runtime.FuncForPC(addr); f != nil && strings.HasPrefix(f.Name(), "runtime.") {
  						continue
  					}
  					// Found non-runtime. Show any runtime uses above it.
  					hideRuntime = false
  				}
  				l := b.locForPC(addr)
  				if l == 0 { // runtime.goexit
  					continue
  				}
  				locs = append(locs, l)
  			}
  			if len(locs) > 0 {
  				break
  			}
  			hideRuntime = false // try again, and show all frames
  		}
  
  		values[0], values[1] = scaleHeapSample(r.AllocObjects, r.AllocBytes, rate)
  		values[2], values[3] = scaleHeapSample(r.InUseObjects(), r.InUseBytes(), rate)
  		var blockSize int64
  		if values[0] > 0 {
  			blockSize = values[1] / values[0]
  		}
  		b.pbSample(values, locs, func() {
  			if blockSize != 0 {
  				b.pbLabel(tagSample_Label, "bytes", "", blockSize)
  			}
  		})
  	}
  	b.build()
  	return nil
  }
  
  // scaleHeapSample adjusts the data from a heap Sample to
  // account for its probability of appearing in the collected
  // data. heap profiles are a sampling of the memory allocations
  // requests in a program. We estimate the unsampled value by dividing
  // each collected sample by its probability of appearing in the
  // profile. heap profiles rely on a poisson process to determine
  // 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 {
  		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
  	}
  
  	avgSize := float64(size) / float64(count)
  	scale := 1 / (1 - math.Exp(-avgSize/float64(rate)))
  
  	return int64(float64(count) * scale), int64(float64(size) * scale)
  }
  

View as plain text