golang.org/toolchain@v0.0.1-go1.9rc2.windows-amd64/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.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 "os" 20 "strings" 21 22 "github.com/google/pprof/internal/binutils" 23 "github.com/google/pprof/internal/plugin" 24 ) 25 26 type source struct { 27 Sources []string 28 ExecName string 29 BuildID string 30 Base []string 31 32 Seconds int 33 Timeout int 34 Symbolize string 35 } 36 37 // Parse parses the command lines through the specified flags package 38 // and returns the source of the profile and optionally the command 39 // for the kind of report to generate (nil for interactive use). 40 func parseFlags(o *plugin.Options) (*source, []string, error) { 41 flag := o.Flagset 42 // Comparisons. 43 flagBase := flag.StringList("base", "", "Source for base profile for comparison") 44 // Internal options. 45 flagSymbolize := flag.String("symbolize", "", "Options for profile symbolization") 46 flagBuildID := flag.String("buildid", "", "Override build id for first mapping") 47 // CPU profile options 48 flagSeconds := flag.Int("seconds", -1, "Length of time for dynamic profiles") 49 // Heap profile options 50 flagInUseSpace := flag.Bool("inuse_space", false, "Display in-use memory size") 51 flagInUseObjects := flag.Bool("inuse_objects", false, "Display in-use object counts") 52 flagAllocSpace := flag.Bool("alloc_space", false, "Display allocated memory size") 53 flagAllocObjects := flag.Bool("alloc_objects", false, "Display allocated object counts") 54 // Contention profile options 55 flagTotalDelay := flag.Bool("total_delay", false, "Display total delay at each region") 56 flagContentions := flag.Bool("contentions", false, "Display number of delays at each region") 57 flagMeanDelay := flag.Bool("mean_delay", false, "Display mean delay at each region") 58 flagTools := flag.String("tools", os.Getenv("PPROF_TOOLS"), "Path for object tool pathnames") 59 60 flagTimeout := flag.Int("timeout", -1, "Timeout in seconds for fetching a profile") 61 62 // Flags used during command processing 63 installedFlags := installFlags(flag) 64 65 flagCommands := make(map[string]*bool) 66 flagParamCommands := make(map[string]*string) 67 for name, cmd := range pprofCommands { 68 if cmd.hasParam { 69 flagParamCommands[name] = flag.String(name, "", "Generate a report in "+name+" format, matching regexp") 70 } else { 71 flagCommands[name] = flag.Bool(name, false, "Generate a report in "+name+" format") 72 } 73 } 74 75 args := flag.Parse(func() { 76 o.UI.Print(usageMsgHdr + 77 usage(true) + 78 usageMsgSrc + 79 flag.ExtraUsage() + 80 usageMsgVars) 81 }) 82 if len(args) == 0 { 83 return nil, nil, fmt.Errorf("no profile source specified") 84 } 85 86 var execName string 87 // Recognize first argument as an executable or buildid override. 88 if len(args) > 1 { 89 arg0 := args[0] 90 if file, err := o.Obj.Open(arg0, 0, ^uint64(0), 0); err == nil { 91 file.Close() 92 execName = arg0 93 args = args[1:] 94 } else if *flagBuildID == "" && isBuildID(arg0) { 95 *flagBuildID = arg0 96 args = args[1:] 97 } 98 } 99 100 // Report conflicting options 101 if err := updateFlags(installedFlags); err != nil { 102 return nil, nil, err 103 } 104 105 cmd, err := outputFormat(flagCommands, flagParamCommands) 106 if err != nil { 107 return nil, nil, err 108 } 109 110 si := pprofVariables["sample_index"].value 111 si = sampleIndex(flagTotalDelay, si, "delay", "-total_delay", o.UI) 112 si = sampleIndex(flagMeanDelay, si, "delay", "-mean_delay", o.UI) 113 si = sampleIndex(flagContentions, si, "contentions", "-contentions", o.UI) 114 si = sampleIndex(flagInUseSpace, si, "inuse_space", "-inuse_space", o.UI) 115 si = sampleIndex(flagInUseObjects, si, "inuse_objects", "-inuse_objects", o.UI) 116 si = sampleIndex(flagAllocSpace, si, "alloc_space", "-alloc_space", o.UI) 117 si = sampleIndex(flagAllocObjects, si, "alloc_objects", "-alloc_objects", o.UI) 118 pprofVariables.set("sample_index", si) 119 120 if *flagMeanDelay { 121 pprofVariables.set("mean", "true") 122 } 123 124 source := &source{ 125 Sources: args, 126 ExecName: execName, 127 BuildID: *flagBuildID, 128 Seconds: *flagSeconds, 129 Timeout: *flagTimeout, 130 Symbolize: *flagSymbolize, 131 } 132 133 for _, s := range *flagBase { 134 if *s != "" { 135 source.Base = append(source.Base, *s) 136 } 137 } 138 139 if bu, ok := o.Obj.(*binutils.Binutils); ok { 140 bu.SetTools(*flagTools) 141 } 142 return source, cmd, nil 143 } 144 145 // installFlags creates command line flags for pprof variables. 146 func installFlags(flag plugin.FlagSet) flagsInstalled { 147 f := flagsInstalled{ 148 ints: make(map[string]*int), 149 bools: make(map[string]*bool), 150 floats: make(map[string]*float64), 151 strings: make(map[string]*string), 152 } 153 for n, v := range pprofVariables { 154 switch v.kind { 155 case boolKind: 156 if v.group != "" { 157 // Set all radio variables to false to identify conflicts. 158 f.bools[n] = flag.Bool(n, false, v.help) 159 } else { 160 f.bools[n] = flag.Bool(n, v.boolValue(), v.help) 161 } 162 case intKind: 163 f.ints[n] = flag.Int(n, v.intValue(), v.help) 164 case floatKind: 165 f.floats[n] = flag.Float64(n, v.floatValue(), v.help) 166 case stringKind: 167 f.strings[n] = flag.String(n, v.value, v.help) 168 } 169 } 170 return f 171 } 172 173 // updateFlags updates the pprof variables according to the flags 174 // parsed in the command line. 175 func updateFlags(f flagsInstalled) error { 176 vars := pprofVariables 177 groups := map[string]string{} 178 for n, v := range f.bools { 179 vars.set(n, fmt.Sprint(*v)) 180 if *v { 181 g := vars[n].group 182 if g != "" && groups[g] != "" { 183 return fmt.Errorf("conflicting options %q and %q set", n, groups[g]) 184 } 185 groups[g] = n 186 } 187 } 188 for n, v := range f.ints { 189 vars.set(n, fmt.Sprint(*v)) 190 } 191 for n, v := range f.floats { 192 vars.set(n, fmt.Sprint(*v)) 193 } 194 for n, v := range f.strings { 195 vars.set(n, *v) 196 } 197 return nil 198 } 199 200 type flagsInstalled struct { 201 ints map[string]*int 202 bools map[string]*bool 203 floats map[string]*float64 204 strings map[string]*string 205 } 206 207 // isBuildID determines if the profile may contain a build ID, by 208 // checking that it is a string of hex digits. 209 func isBuildID(id string) bool { 210 return strings.Trim(id, "0123456789abcdefABCDEF") == "" 211 } 212 213 func sampleIndex(flag *bool, si string, sampleType, option string, ui plugin.UI) string { 214 if *flag { 215 if si == "" { 216 return sampleType 217 } 218 ui.PrintErr("Multiple value selections, ignoring ", option) 219 } 220 return si 221 } 222 223 func outputFormat(bcmd map[string]*bool, acmd map[string]*string) (cmd []string, err error) { 224 for n, b := range bcmd { 225 if *b { 226 if cmd != nil { 227 return nil, fmt.Errorf("must set at most one output format") 228 } 229 cmd = []string{n} 230 } 231 } 232 for n, s := range acmd { 233 if *s != "" { 234 if cmd != nil { 235 return nil, fmt.Errorf("must set at most one output format") 236 } 237 cmd = []string{n, *s} 238 } 239 } 240 return cmd, nil 241 } 242 243 var usageMsgHdr = "usage: pprof [options] [-base source] [binary] <source> ...\n" 244 245 var usageMsgSrc = "\n\n" + 246 " Source options:\n" + 247 " -seconds Duration for time-based profile collection\n" + 248 " -timeout Timeout in seconds for profile collection\n" + 249 " -buildid Override build id for main binary\n" + 250 " -base source Source of profile to use as baseline\n" + 251 " profile.pb.gz Profile in compressed protobuf format\n" + 252 " legacy_profile Profile in legacy pprof format\n" + 253 " http://host/profile URL for profile handler to retrieve\n" + 254 " -symbolize= Controls source of symbol information\n" + 255 " none Do not attempt symbolization\n" + 256 " local Examine only local binaries\n" + 257 " fastlocal Only get function names from local binaries\n" + 258 " remote Do not examine local binaries\n" + 259 " force Force re-symbolization\n" + 260 " Binary Local path or build id of binary for symbolization\n" 261 262 var usageMsgVars = "\n\n" + 263 " Misc options:\n" + 264 " -tools Search path for object tools\n" + 265 "\n" + 266 " Environment Variables:\n" + 267 " PPROF_TMPDIR Location for saved profiles (default $HOME/pprof)\n" + 268 " PPROF_TOOLS Search path for object-level tools\n" + 269 " PPROF_BINARY_PATH Search path for local binary files\n" + 270 " default: $HOME/pprof/binaries\n" + 271 " finds binaries by $name and $buildid/$name\n" + 272 " * On Windows, %USERPROFILE% is used instead of $HOME"