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 }