golang.org/toolchain@v0.0.1-go1.9rc2.windows-amd64/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_focus.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 package driver 16 17 import ( 18 "fmt" 19 "regexp" 20 "strconv" 21 "strings" 22 23 "github.com/google/pprof/internal/measurement" 24 "github.com/google/pprof/internal/plugin" 25 "github.com/google/pprof/profile" 26 ) 27 28 var tagFilterRangeRx = regexp.MustCompile("([[:digit:]]+)([[:alpha:]]+)") 29 30 // applyFocus filters samples based on the focus/ignore options 31 func applyFocus(prof *profile.Profile, v variables, ui plugin.UI) error { 32 focus, err := compileRegexOption("focus", v["focus"].value, nil) 33 ignore, err := compileRegexOption("ignore", v["ignore"].value, err) 34 hide, err := compileRegexOption("hide", v["hide"].value, err) 35 show, err := compileRegexOption("show", v["show"].value, err) 36 tagfocus, err := compileTagFilter("tagfocus", v["tagfocus"].value, ui, err) 37 tagignore, err := compileTagFilter("tagignore", v["tagignore"].value, ui, err) 38 prunefrom, err := compileRegexOption("prune_from", v["prune_from"].value, err) 39 if err != nil { 40 return err 41 } 42 43 fm, im, hm, hnm := prof.FilterSamplesByName(focus, ignore, hide, show) 44 warnNoMatches(focus == nil || fm, "Focus", ui) 45 warnNoMatches(ignore == nil || im, "Ignore", ui) 46 warnNoMatches(hide == nil || hm, "Hide", ui) 47 warnNoMatches(show == nil || hnm, "Show", ui) 48 49 tfm, tim := prof.FilterSamplesByTag(tagfocus, tagignore) 50 warnNoMatches(tagfocus == nil || tfm, "TagFocus", ui) 51 warnNoMatches(tagignore == nil || tim, "TagIgnore", ui) 52 53 tagshow, err := compileRegexOption("tagshow", v["tagshow"].value, err) 54 taghide, err := compileRegexOption("taghide", v["taghide"].value, err) 55 tns, tnh := prof.FilterTagsByName(tagshow, taghide) 56 warnNoMatches(tagshow == nil || tns, "TagShow", ui) 57 warnNoMatches(tagignore == nil || tnh, "TagHide", ui) 58 59 if prunefrom != nil { 60 prof.PruneFrom(prunefrom) 61 } 62 return nil 63 } 64 65 func compileRegexOption(name, value string, err error) (*regexp.Regexp, error) { 66 if value == "" || err != nil { 67 return nil, err 68 } 69 rx, err := regexp.Compile(value) 70 if err != nil { 71 return nil, fmt.Errorf("parsing %s regexp: %v", name, err) 72 } 73 return rx, nil 74 } 75 76 func compileTagFilter(name, value string, ui plugin.UI, err error) (func(*profile.Sample) bool, error) { 77 if value == "" || err != nil { 78 return nil, err 79 } 80 if numFilter := parseTagFilterRange(value); numFilter != nil { 81 ui.PrintErr(name, ":Interpreted '", value, "' as range, not regexp") 82 return func(s *profile.Sample) bool { 83 for key, vals := range s.NumLabel { 84 for _, val := range vals { 85 if numFilter(val, key) { 86 return true 87 } 88 } 89 } 90 return false 91 }, nil 92 } 93 var rfx []*regexp.Regexp 94 for _, tagf := range strings.Split(value, ",") { 95 fx, err := regexp.Compile(tagf) 96 if err != nil { 97 return nil, fmt.Errorf("parsing %s regexp: %v", name, err) 98 } 99 rfx = append(rfx, fx) 100 } 101 return func(s *profile.Sample) bool { 102 matchedrx: 103 for _, rx := range rfx { 104 for key, vals := range s.Label { 105 for _, val := range vals { 106 if rx.MatchString(key + ":" + val) { 107 continue matchedrx 108 } 109 } 110 } 111 return false 112 } 113 return true 114 }, nil 115 } 116 117 // parseTagFilterRange returns a function to checks if a value is 118 // contained on the range described by a string. It can recognize 119 // strings of the form: 120 // "32kb" -- matches values == 32kb 121 // ":64kb" -- matches values <= 64kb 122 // "4mb:" -- matches values >= 4mb 123 // "12kb:64mb" -- matches values between 12kb and 64mb (both included). 124 func parseTagFilterRange(filter string) func(int64, string) bool { 125 ranges := tagFilterRangeRx.FindAllStringSubmatch(filter, 2) 126 if len(ranges) == 0 { 127 return nil // No ranges were identified 128 } 129 v, err := strconv.ParseInt(ranges[0][1], 10, 64) 130 if err != nil { 131 panic(fmt.Errorf("Failed to parse int %s: %v", ranges[0][1], err)) 132 } 133 scaledValue, unit := measurement.Scale(v, ranges[0][2], ranges[0][2]) 134 if len(ranges) == 1 { 135 switch match := ranges[0][0]; filter { 136 case match: 137 return func(v int64, u string) bool { 138 sv, su := measurement.Scale(v, u, unit) 139 return su == unit && sv == scaledValue 140 } 141 case match + ":": 142 return func(v int64, u string) bool { 143 sv, su := measurement.Scale(v, u, unit) 144 return su == unit && sv >= scaledValue 145 } 146 case ":" + match: 147 return func(v int64, u string) bool { 148 sv, su := measurement.Scale(v, u, unit) 149 return su == unit && sv <= scaledValue 150 } 151 } 152 return nil 153 } 154 if filter != ranges[0][0]+":"+ranges[1][0] { 155 return nil 156 } 157 if v, err = strconv.ParseInt(ranges[1][1], 10, 64); err != nil { 158 panic(fmt.Errorf("Failed to parse int %s: %v", ranges[1][1], err)) 159 } 160 scaledValue2, unit2 := measurement.Scale(v, ranges[1][2], unit) 161 if unit != unit2 { 162 return nil 163 } 164 return func(v int64, u string) bool { 165 sv, su := measurement.Scale(v, u, unit) 166 return su == unit && sv >= scaledValue && sv <= scaledValue2 167 } 168 } 169 170 func warnNoMatches(match bool, option string, ui plugin.UI) { 171 if !match { 172 ui.PrintErr(option + " expression matched no samples") 173 } 174 }