Source file src/internal/profile/prune.go

     1  // Copyright 2014 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  // Implements methods to remove frames from profiles.
     6  
     7  package profile
     8  
     9  import (
    10  	"fmt"
    11  	"regexp"
    12  )
    13  
    14  // Prune removes all nodes beneath a node matching dropRx, and not
    15  // matching keepRx. If the root node of a Sample matches, the sample
    16  // will have an empty stack.
    17  func (p *Profile) Prune(dropRx, keepRx *regexp.Regexp) {
    18  	prune := make(map[uint64]bool)
    19  	pruneBeneath := make(map[uint64]bool)
    20  
    21  	for _, loc := range p.Location {
    22  		var i int
    23  		for i = len(loc.Line) - 1; i >= 0; i-- {
    24  			if fn := loc.Line[i].Function; fn != nil && fn.Name != "" {
    25  				funcName := fn.Name
    26  				// Account for leading '.' on the PPC ELF v1 ABI.
    27  				if funcName[0] == '.' {
    28  					funcName = funcName[1:]
    29  				}
    30  				if dropRx.MatchString(funcName) {
    31  					if keepRx == nil || !keepRx.MatchString(funcName) {
    32  						break
    33  					}
    34  				}
    35  			}
    36  		}
    37  
    38  		if i >= 0 {
    39  			// Found matching entry to prune.
    40  			pruneBeneath[loc.ID] = true
    41  
    42  			// Remove the matching location.
    43  			if i == len(loc.Line)-1 {
    44  				// Matched the top entry: prune the whole location.
    45  				prune[loc.ID] = true
    46  			} else {
    47  				loc.Line = loc.Line[i+1:]
    48  			}
    49  		}
    50  	}
    51  
    52  	// Prune locs from each Sample
    53  	for _, sample := range p.Sample {
    54  		// Scan from the root to the leaves to find the prune location.
    55  		// Do not prune frames before the first user frame, to avoid
    56  		// pruning everything.
    57  		foundUser := false
    58  		for i := len(sample.Location) - 1; i >= 0; i-- {
    59  			id := sample.Location[i].ID
    60  			if !prune[id] && !pruneBeneath[id] {
    61  				foundUser = true
    62  				continue
    63  			}
    64  			if !foundUser {
    65  				continue
    66  			}
    67  			if prune[id] {
    68  				sample.Location = sample.Location[i+1:]
    69  				break
    70  			}
    71  			if pruneBeneath[id] {
    72  				sample.Location = sample.Location[i:]
    73  				break
    74  			}
    75  		}
    76  	}
    77  }
    78  
    79  // RemoveUninteresting prunes and elides profiles using built-in
    80  // tables of uninteresting function names.
    81  func (p *Profile) RemoveUninteresting() error {
    82  	var keep, drop *regexp.Regexp
    83  	var err error
    84  
    85  	if p.DropFrames != "" {
    86  		if drop, err = regexp.Compile("^(" + p.DropFrames + ")$"); err != nil {
    87  			return fmt.Errorf("failed to compile regexp %s: %v", p.DropFrames, err)
    88  		}
    89  		if p.KeepFrames != "" {
    90  			if keep, err = regexp.Compile("^(" + p.KeepFrames + ")$"); err != nil {
    91  				return fmt.Errorf("failed to compile regexp %s: %v", p.KeepFrames, err)
    92  			}
    93  		}
    94  		p.Prune(drop, keep)
    95  	}
    96  	return nil
    97  }
    98  

View as plain text