1
2
3
4
5
6
7
8
9
10
11
12
13
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
31 func applyFocus(prof *profile.Profile, numLabelUnits map[string]string, cfg config, ui plugin.UI) error {
32 focus, err := compileRegexOption("focus", cfg.Focus, nil)
33 ignore, err := compileRegexOption("ignore", cfg.Ignore, err)
34 hide, err := compileRegexOption("hide", cfg.Hide, err)
35 show, err := compileRegexOption("show", cfg.Show, err)
36 showfrom, err := compileRegexOption("show_from", cfg.ShowFrom, err)
37 tagfocus, err := compileTagFilter("tagfocus", cfg.TagFocus, numLabelUnits, ui, err)
38 tagignore, err := compileTagFilter("tagignore", cfg.TagIgnore, numLabelUnits, ui, err)
39 prunefrom, err := compileRegexOption("prune_from", cfg.PruneFrom, err)
40 if err != nil {
41 return err
42 }
43
44 fm, im, hm, hnm := prof.FilterSamplesByName(focus, ignore, hide, show)
45 warnNoMatches(focus == nil || fm, "Focus", ui)
46 warnNoMatches(ignore == nil || im, "Ignore", ui)
47 warnNoMatches(hide == nil || hm, "Hide", ui)
48 warnNoMatches(show == nil || hnm, "Show", ui)
49
50 sfm := prof.ShowFrom(showfrom)
51 warnNoMatches(showfrom == nil || sfm, "ShowFrom", ui)
52
53 tfm, tim := prof.FilterSamplesByTag(tagfocus, tagignore)
54 warnNoMatches(tagfocus == nil || tfm, "TagFocus", ui)
55 warnNoMatches(tagignore == nil || tim, "TagIgnore", ui)
56
57 tagshow, err := compileRegexOption("tagshow", cfg.TagShow, err)
58 taghide, err := compileRegexOption("taghide", cfg.TagHide, err)
59 tns, tnh := prof.FilterTagsByName(tagshow, taghide)
60 warnNoMatches(tagshow == nil || tns, "TagShow", ui)
61 warnNoMatches(taghide == nil || tnh, "TagHide", ui)
62
63 if prunefrom != nil {
64 prof.PruneFrom(prunefrom)
65 }
66 return err
67 }
68
69 func compileRegexOption(name, value string, err error) (*regexp.Regexp, error) {
70 if value == "" || err != nil {
71 return nil, err
72 }
73 rx, err := regexp.Compile(value)
74 if err != nil {
75 return nil, fmt.Errorf("parsing %s regexp: %v", name, err)
76 }
77 return rx, nil
78 }
79
80 func compileTagFilter(name, value string, numLabelUnits map[string]string, ui plugin.UI, err error) (func(*profile.Sample) bool, error) {
81 if value == "" || err != nil {
82 return nil, err
83 }
84
85 tagValuePair := strings.SplitN(value, "=", 2)
86 var wantKey string
87 if len(tagValuePair) == 2 {
88 wantKey = tagValuePair[0]
89 value = tagValuePair[1]
90 }
91
92 if numFilter := parseTagFilterRange(value); numFilter != nil {
93 ui.PrintErr(name, ":Interpreted '", value, "' as range, not regexp")
94 labelFilter := func(vals []int64, unit string) bool {
95 for _, val := range vals {
96 if numFilter(val, unit) {
97 return true
98 }
99 }
100 return false
101 }
102 numLabelUnit := func(key string) string {
103 return numLabelUnits[key]
104 }
105 if wantKey == "" {
106 return func(s *profile.Sample) bool {
107 for key, vals := range s.NumLabel {
108 if labelFilter(vals, numLabelUnit(key)) {
109 return true
110 }
111 }
112 return false
113 }, nil
114 }
115 return func(s *profile.Sample) bool {
116 if vals, ok := s.NumLabel[wantKey]; ok {
117 return labelFilter(vals, numLabelUnit(wantKey))
118 }
119 return false
120 }, nil
121 }
122
123 var rfx []*regexp.Regexp
124 for _, tagf := range strings.Split(value, ",") {
125 fx, err := regexp.Compile(tagf)
126 if err != nil {
127 return nil, fmt.Errorf("parsing %s regexp: %v", name, err)
128 }
129 rfx = append(rfx, fx)
130 }
131 if wantKey == "" {
132 return func(s *profile.Sample) bool {
133 matchedrx:
134 for _, rx := range rfx {
135 for key, vals := range s.Label {
136 for _, val := range vals {
137
138 if rx.MatchString(key + ":" + val) {
139 continue matchedrx
140 }
141 }
142 }
143 return false
144 }
145 return true
146 }, nil
147 }
148 return func(s *profile.Sample) bool {
149 if vals, ok := s.Label[wantKey]; ok {
150 for _, rx := range rfx {
151 for _, val := range vals {
152 if rx.MatchString(val) {
153 return true
154 }
155 }
156 }
157 }
158 return false
159 }, nil
160 }
161
162
163
164
165
166
167
168
169 func parseTagFilterRange(filter string) func(int64, string) bool {
170 ranges := tagFilterRangeRx.FindAllStringSubmatch(filter, 2)
171 if len(ranges) == 0 {
172 return nil
173 }
174 v, err := strconv.ParseInt(ranges[0][1], 10, 64)
175 if err != nil {
176 panic(fmt.Errorf("failed to parse int %s: %v", ranges[0][1], err))
177 }
178 scaledValue, unit := measurement.Scale(v, ranges[0][2], ranges[0][2])
179 if len(ranges) == 1 {
180 switch match := ranges[0][0]; filter {
181 case match:
182 return func(v int64, u string) bool {
183 sv, su := measurement.Scale(v, u, unit)
184 return su == unit && sv == scaledValue
185 }
186 case match + ":":
187 return func(v int64, u string) bool {
188 sv, su := measurement.Scale(v, u, unit)
189 return su == unit && sv >= scaledValue
190 }
191 case ":" + match:
192 return func(v int64, u string) bool {
193 sv, su := measurement.Scale(v, u, unit)
194 return su == unit && sv <= scaledValue
195 }
196 }
197 return nil
198 }
199 if filter != ranges[0][0]+":"+ranges[1][0] {
200 return nil
201 }
202 if v, err = strconv.ParseInt(ranges[1][1], 10, 64); err != nil {
203 panic(fmt.Errorf("failed to parse int %s: %v", ranges[1][1], err))
204 }
205 scaledValue2, unit2 := measurement.Scale(v, ranges[1][2], unit)
206 if unit != unit2 {
207 return nil
208 }
209 return func(v int64, u string) bool {
210 sv, su := measurement.Scale(v, u, unit)
211 return su == unit && sv >= scaledValue && sv <= scaledValue2
212 }
213 }
214
215 func warnNoMatches(match bool, option string, ui plugin.UI) {
216 if !match {
217 ui.PrintErr(option + " expression matched no samples")
218 }
219 }
220
View as plain text