golang.org/toolchain@v0.0.1-go1.9rc2.windows-amd64/src/cmd/vendor/github.com/google/pprof/profile/prune.go (about)

     1  // Copyright 2014 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Implements methods to remove frames from profiles.
    16  
    17  package profile
    18  
    19  import (
    20  	"fmt"
    21  	"regexp"
    22  	"strings"
    23  )
    24  
    25  // Prune removes all nodes beneath a node matching dropRx, and not
    26  // matching keepRx. If the root node of a Sample matches, the sample
    27  // will have an empty stack.
    28  func (p *Profile) Prune(dropRx, keepRx *regexp.Regexp) {
    29  	prune := make(map[uint64]bool)
    30  	pruneBeneath := make(map[uint64]bool)
    31  
    32  	for _, loc := range p.Location {
    33  		var i int
    34  		for i = len(loc.Line) - 1; i >= 0; i-- {
    35  			if fn := loc.Line[i].Function; fn != nil && fn.Name != "" {
    36  				// Account for leading '.' on the PPC ELF v1 ABI.
    37  				funcName := strings.TrimPrefix(fn.Name, ".")
    38  				// Account for unsimplified names -- trim starting from the first '('.
    39  				if index := strings.Index(funcName, "("); index > 0 {
    40  					funcName = funcName[:index]
    41  				}
    42  				if dropRx.MatchString(funcName) {
    43  					if keepRx == nil || !keepRx.MatchString(funcName) {
    44  						break
    45  					}
    46  				}
    47  			}
    48  		}
    49  
    50  		if i >= 0 {
    51  			// Found matching entry to prune.
    52  			pruneBeneath[loc.ID] = true
    53  
    54  			// Remove the matching location.
    55  			if i == len(loc.Line)-1 {
    56  				// Matched the top entry: prune the whole location.
    57  				prune[loc.ID] = true
    58  			} else {
    59  				loc.Line = loc.Line[i+1:]
    60  			}
    61  		}
    62  	}
    63  
    64  	// Prune locs from each Sample
    65  	for _, sample := range p.Sample {
    66  		// Scan from the root to the leaves to find the prune location.
    67  		// Do not prune frames before the first user frame, to avoid
    68  		// pruning everything.
    69  		foundUser := false
    70  		for i := len(sample.Location) - 1; i >= 0; i-- {
    71  			id := sample.Location[i].ID
    72  			if !prune[id] && !pruneBeneath[id] {
    73  				foundUser = true
    74  				continue
    75  			}
    76  			if !foundUser {
    77  				continue
    78  			}
    79  			if prune[id] {
    80  				sample.Location = sample.Location[i+1:]
    81  				break
    82  			}
    83  			if pruneBeneath[id] {
    84  				sample.Location = sample.Location[i:]
    85  				break
    86  			}
    87  		}
    88  	}
    89  }
    90  
    91  // RemoveUninteresting prunes and elides profiles using built-in
    92  // tables of uninteresting function names.
    93  func (p *Profile) RemoveUninteresting() error {
    94  	var keep, drop *regexp.Regexp
    95  	var err error
    96  
    97  	if p.DropFrames != "" {
    98  		if drop, err = regexp.Compile("^(" + p.DropFrames + ")$"); err != nil {
    99  			return fmt.Errorf("failed to compile regexp %s: %v", p.DropFrames, err)
   100  		}
   101  		if p.KeepFrames != "" {
   102  			if keep, err = regexp.Compile("^(" + p.KeepFrames + ")$"); err != nil {
   103  				return fmt.Errorf("failed to compile regexp %s: %v", p.KeepFrames, err)
   104  			}
   105  		}
   106  		p.Prune(drop, keep)
   107  	}
   108  	return nil
   109  }
   110  
   111  // PruneFrom removes all nodes beneath the lowest node matching dropRx, not including itself.
   112  //
   113  // Please see the example below to understand this method as well as
   114  // the difference from Prune method.
   115  //
   116  // A sample contains Location of [A,B,C,B,D] where D is the top frame and there's no inline.
   117  //
   118  // PruneFrom(A) returns [A,B,C,B,D] because there's no node beneath A.
   119  // Prune(A, nil) returns [B,C,B,D] by removing A itself.
   120  //
   121  // PruneFrom(B) returns [B,C,B,D] by removing all nodes beneath the first B when scanning from the bottom.
   122  // Prune(B, nil) returns [D] because a matching node is found by scanning from the root.
   123  func (p *Profile) PruneFrom(dropRx *regexp.Regexp) {
   124  	pruneBeneath := make(map[uint64]bool)
   125  
   126  	for _, loc := range p.Location {
   127  		for i := 0; i < len(loc.Line); i++ {
   128  			if fn := loc.Line[i].Function; fn != nil && fn.Name != "" {
   129  				// Account for leading '.' on the PPC ELF v1 ABI.
   130  				funcName := strings.TrimPrefix(fn.Name, ".")
   131  				// Account for unsimplified names -- trim starting from the first '('.
   132  				if index := strings.Index(funcName, "("); index > 0 {
   133  					funcName = funcName[:index]
   134  				}
   135  				if dropRx.MatchString(funcName) {
   136  					// Found matching entry to prune.
   137  					pruneBeneath[loc.ID] = true
   138  					loc.Line = loc.Line[i:]
   139  					break
   140  				}
   141  			}
   142  		}
   143  	}
   144  
   145  	// Prune locs from each Sample
   146  	for _, sample := range p.Sample {
   147  		// Scan from the bottom leaf to the root to find the prune location.
   148  		for i, loc := range sample.Location {
   149  			if pruneBeneath[loc.ID] {
   150  				sample.Location = sample.Location[i:]
   151  				break
   152  			}
   153  		}
   154  	}
   155  }