github.com/JimmyHuang454/JLS-go@v0.0.0-20230831150107-90d536585ba0/internal/profile/prune.go (about) 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 }