Source file src/cmd/vendor/github.com/google/pprof/internal/driver/tagroot.go

     1  package driver
     2  
     3  import (
     4  	"strings"
     5  
     6  	"github.com/google/pprof/internal/measurement"
     7  	"github.com/google/pprof/profile"
     8  )
     9  
    10  // addLabelNodes adds pseudo stack frames "label:value" to each Sample with
    11  // labels matching the supplied keys.
    12  //
    13  // rootKeys adds frames at the root of the callgraph (first key becomes new root).
    14  // leafKeys adds frames at the leaf of the callgraph (last key becomes new leaf).
    15  //
    16  // Returns whether there were matches found for the label keys.
    17  func addLabelNodes(p *profile.Profile, rootKeys, leafKeys []string, outputUnit string) (rootm, leafm bool) {
    18  	// Find where to insert the new locations and functions at the end of
    19  	// their ID spaces.
    20  	var maxLocID uint64
    21  	var maxFunctionID uint64
    22  	for _, loc := range p.Location {
    23  		if loc.ID > maxLocID {
    24  			maxLocID = loc.ID
    25  		}
    26  	}
    27  	for _, f := range p.Function {
    28  		if f.ID > maxFunctionID {
    29  			maxFunctionID = f.ID
    30  		}
    31  	}
    32  	nextLocID := maxLocID + 1
    33  	nextFuncID := maxFunctionID + 1
    34  
    35  	// Intern the new locations and functions we are generating.
    36  	type locKey struct {
    37  		functionName, fileName string
    38  	}
    39  	locs := map[locKey]*profile.Location{}
    40  
    41  	internLoc := func(locKey locKey) *profile.Location {
    42  		loc, found := locs[locKey]
    43  		if found {
    44  			return loc
    45  		}
    46  
    47  		function := &profile.Function{
    48  			ID:       nextFuncID,
    49  			Name:     locKey.functionName,
    50  			Filename: locKey.fileName,
    51  		}
    52  		nextFuncID++
    53  		p.Function = append(p.Function, function)
    54  
    55  		loc = &profile.Location{
    56  			ID: nextLocID,
    57  			Line: []profile.Line{
    58  				{
    59  					Function: function,
    60  				},
    61  			},
    62  		}
    63  		nextLocID++
    64  		p.Location = append(p.Location, loc)
    65  		locs[locKey] = loc
    66  		return loc
    67  	}
    68  
    69  	makeLabelLocs := func(s *profile.Sample, keys []string) ([]*profile.Location, bool) {
    70  		var locs []*profile.Location
    71  		var match bool
    72  		for i := range keys {
    73  			// Loop backwards, ensuring the first tag is closest to the root,
    74  			// and the last tag is closest to the leaves.
    75  			k := keys[len(keys)-1-i]
    76  			values := formatLabelValues(s, k, outputUnit)
    77  			if len(values) > 0 {
    78  				match = true
    79  			}
    80  			locKey := locKey{
    81  				functionName: strings.Join(values, ","),
    82  				fileName:     k,
    83  			}
    84  			loc := internLoc(locKey)
    85  			locs = append(locs, loc)
    86  		}
    87  		return locs, match
    88  	}
    89  
    90  	for _, s := range p.Sample {
    91  		rootsToAdd, sampleMatchedRoot := makeLabelLocs(s, rootKeys)
    92  		if sampleMatchedRoot {
    93  			rootm = true
    94  		}
    95  		leavesToAdd, sampleMatchedLeaf := makeLabelLocs(s, leafKeys)
    96  		if sampleMatchedLeaf {
    97  			leafm = true
    98  		}
    99  
   100  		if len(leavesToAdd)+len(rootsToAdd) == 0 {
   101  			continue
   102  		}
   103  
   104  		var newLocs []*profile.Location
   105  		newLocs = append(newLocs, leavesToAdd...)
   106  		newLocs = append(newLocs, s.Location...)
   107  		newLocs = append(newLocs, rootsToAdd...)
   108  		s.Location = newLocs
   109  	}
   110  	return
   111  }
   112  
   113  // formatLabelValues returns all the string and numeric labels in Sample, with
   114  // the numeric labels formatted according to outputUnit.
   115  func formatLabelValues(s *profile.Sample, k string, outputUnit string) []string {
   116  	var values []string
   117  	values = append(values, s.Label[k]...)
   118  	numLabels := s.NumLabel[k]
   119  	numUnits := s.NumUnit[k]
   120  	if len(numLabels) != len(numUnits) && len(numUnits) != 0 {
   121  		return values
   122  	}
   123  	for i, numLabel := range numLabels {
   124  		var value string
   125  		if len(numUnits) != 0 {
   126  			value = measurement.ScaledLabel(numLabel, numUnits[i], outputUnit)
   127  		} else {
   128  			value = measurement.ScaledLabel(numLabel, "", "")
   129  		}
   130  		values = append(values, value)
   131  	}
   132  	return values
   133  }
   134  

View as plain text