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  }