...
Run Format

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  		locs = locs[:0]
    31  		hideRuntime := true
    32  		for tries := 0; tries < 2; tries++ {
    33  			for _, addr := range r.Stack() {
    34  				// For heap profiles, all stack
    35  				// addresses are return PCs, which is
    36  				// what locForPC expects.
    37  				if hideRuntime {
    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  					hideRuntime = false
    43  				}
    44  				l := b.locForPC(addr)
    45  				if l == 0 { // runtime.goexit
    46  					continue
    47  				}
    48  				locs = append(locs, l)
    49  			}
    50  			if len(locs) > 0 {
    51  				break
    52  			}
    53  			hideRuntime = false // try again, and show all frames
    54  		}
    55  
    56  		values[0], values[1] = scaleHeapSample(r.AllocObjects, r.AllocBytes, rate)
    57  		values[2], values[3] = scaleHeapSample(r.InUseObjects(), r.InUseBytes(), rate)
    58  		var blockSize int64
    59  		if values[0] > 0 {
    60  			blockSize = values[1] / values[0]
    61  		}
    62  		b.pbSample(values, locs, func() {
    63  			if blockSize != 0 {
    64  				b.pbLabel(tagSample_Label, "bytes", "", blockSize)
    65  			}
    66  		})
    67  	}
    68  	b.build()
    69  	return nil
    70  }
    71  
    72  // scaleHeapSample adjusts the data from a heap Sample to
    73  // account for its probability of appearing in the collected
    74  // data. heap profiles are a sampling of the memory allocations
    75  // requests in a program. We estimate the unsampled value by dividing
    76  // each collected sample by its probability of appearing in the
    77  // profile. heap profiles rely on a poisson process to determine
    78  // which samples to collect, based on the desired average collection
    79  // rate R. The probability of a sample of size S to appear in that
    80  // profile is 1-exp(-S/R).
    81  func scaleHeapSample(count, size, rate int64) (int64, int64) {
    82  	if count == 0 || size == 0 {
    83  		return 0, 0
    84  	}
    85  
    86  	if rate <= 1 {
    87  		// if rate==1 all samples were collected so no adjustment is needed.
    88  		// if rate<1 treat as unknown and skip scaling.
    89  		return count, size
    90  	}
    91  
    92  	avgSize := float64(size) / float64(count)
    93  	scale := 1 / (1 - math.Exp(-avgSize/float64(rate)))
    94  
    95  	return int64(float64(count) * scale), int64(float64(size) * scale)
    96  }
    97  

View as plain text