ソースを参照

Merge pull request #34 from rauls5382/options

Add "options" command
Josef Jelinek 8 年 前
コミット
f8a8a7333f
共有2 個のファイルを変更した75 個の追加33 個の削除を含む
  1. 6
    0
      internal/driver/commands.go
  2. 69
    33
      internal/driver/interactive.go

+ 6
- 0
internal/driver/commands.go ファイルの表示

@@ -268,6 +268,7 @@ func usage(commandLine bool) string {
268 268
 		help = "  Output formats (select only one):\n"
269 269
 	} else {
270 270
 		help = "  Commands:\n"
271
+		commands = append(commands, fmtHelp("o/options", "List options and their current values"))
271 272
 		commands = append(commands, fmtHelp("quit/exit/^D", "Exit pprof"))
272 273
 	}
273 274
 
@@ -534,6 +535,11 @@ func (vars variables) set(name, value string) error {
534 535
 		_, err = strconv.Atoi(value)
535 536
 	case floatKind:
536 537
 		_, err = strconv.ParseFloat(value, 64)
538
+	case stringKind:
539
+		// Remove quotes, particularly useful for empty values.
540
+		if len(value) > 1 && strings.HasPrefix(value, `"`) && strings.HasSuffix(value, `"`) {
541
+			value = value[1 : len(value)-1]
542
+		}
537 543
 	}
538 544
 	if err != nil {
539 545
 		return err

+ 69
- 33
internal/driver/interactive.go ファイルの表示

@@ -26,6 +26,8 @@ import (
26 26
 	"github.com/google/pprof/profile"
27 27
 )
28 28
 
29
+var commentStart = "//:" // Sentinel for comments on options
30
+
29 31
 // interactive starts a shell to read pprof commands.
30 32
 func interactive(p *profile.Profile, o *plugin.Options) error {
31 33
 	// Enter command processing loop.
@@ -40,7 +42,7 @@ func interactive(p *profile.Profile, o *plugin.Options) error {
40 42
 
41 43
 	greetings(p, o.UI)
42 44
 	for {
43
-		input, err := o.UI.ReadLine(pprofPrompt(p))
45
+		input, err := o.UI.ReadLine("(pprof) ")
44 46
 		if err != nil {
45 47
 			if err != io.EOF {
46 48
 				return err
@@ -54,17 +56,36 @@ func interactive(p *profile.Profile, o *plugin.Options) error {
54 56
 			// Process assignments of the form variable=value
55 57
 			if s := strings.SplitN(input, "=", 2); len(s) > 0 {
56 58
 				name := strings.TrimSpace(s[0])
57
-
59
+				var value string
60
+				if len(s) == 2 {
61
+					value = s[1]
62
+					if comment := strings.LastIndex(value, commentStart); comment != -1 {
63
+						value = value[:comment]
64
+					}
65
+					value = strings.TrimSpace(value)
66
+				}
58 67
 				if v := pprofVariables[name]; v != nil {
59
-					var value string
60
-					if len(s) == 2 {
61
-						value = strings.TrimSpace(s[1])
68
+					if name == "sample_index" {
69
+						// Error check sample_index=xxx to ensure xxx is a valid sample type.
70
+						index, err := locateSampleIndex(p, value)
71
+						if err != nil {
72
+							o.UI.PrintErr(err)
73
+							continue
74
+						}
75
+						value = p.SampleType[index].Type
62 76
 					}
63 77
 					if err := pprofVariables.set(name, value); err != nil {
64 78
 						o.UI.PrintErr(err)
65 79
 					}
66 80
 					continue
67 81
 				}
82
+				// Allow group=variable syntax by converting into variable="".
83
+				if v := pprofVariables[value]; v != nil && v.group == name {
84
+					if err := pprofVariables.set(value, ""); err != nil {
85
+						o.UI.PrintErr(err)
86
+					}
87
+					continue
88
+				}
68 89
 			}
69 90
 
70 91
 			tokens := strings.Fields(input)
@@ -73,6 +94,9 @@ func interactive(p *profile.Profile, o *plugin.Options) error {
73 94
 			}
74 95
 
75 96
 			switch tokens[0] {
97
+			case "o", "options":
98
+				printCurrentOptions(p, o.UI)
99
+				continue
76 100
 			case "exit", "quit":
77 101
 				return nil
78 102
 			case "help":
@@ -100,9 +124,8 @@ func greetings(p *profile.Profile, ui plugin.UI) {
100 124
 	ropt, err := reportOptions(p, pprofVariables)
101 125
 	if err == nil {
102 126
 		ui.Print(strings.Join(report.ProfileLabels(report.New(p, ropt)), "\n"))
103
-		ui.Print(fmt.Sprintf("Sample types: %v\n", sampleTypes(p)))
104 127
 	}
105
-	ui.Print("Entering interactive mode (type \"help\" for commands)")
128
+	ui.Print("Entering interactive mode (type \"help\" for commands, \"o\" for options)")
106 129
 }
107 130
 
108 131
 // shortcuts represents composite commands that expand into a sequence
@@ -110,6 +133,7 @@ func greetings(p *profile.Profile, ui plugin.UI) {
110 133
 type shortcuts map[string][]string
111 134
 
112 135
 func (a shortcuts) expand(input string) []string {
136
+	input = strings.TrimSpace(input)
113 137
 	if a != nil {
114 138
 		if r, ok := a[input]; ok {
115 139
 			return r
@@ -135,45 +159,57 @@ func profileShortcuts(p *profile.Profile) shortcuts {
135 159
 	return s
136 160
 }
137 161
 
138
-// pprofPrompt returns the prompt displayed to accept commands.
139
-// hides some default values to reduce clutter.
140
-func pprofPrompt(p *profile.Profile) string {
162
+func printCurrentOptions(p *profile.Profile, ui plugin.UI) {
141 163
 	var args []string
164
+	type groupInfo struct {
165
+		set    string
166
+		values []string
167
+	}
168
+	groups := make(map[string]*groupInfo)
142 169
 	for n, o := range pprofVariables {
143 170
 		v := o.stringValue()
144
-		if v == "" {
171
+		comment := ""
172
+		if g := o.group; g != "" {
173
+			gi, ok := groups[g]
174
+			if !ok {
175
+				gi = &groupInfo{}
176
+				groups[g] = gi
177
+			}
178
+			if o.boolValue() {
179
+				gi.set = n
180
+			}
181
+			gi.values = append(gi.values, n)
145 182
 			continue
146 183
 		}
147
-		// Do not show some default values.
148 184
 		switch {
149
-		case n == "unit" && v == "minimum":
150
-			continue
151
-		case n == "divide_by" && v == "1":
152
-			continue
153
-		case n == "nodecount" && v == "-1":
154
-			continue
155 185
 		case n == "sample_index":
156
-			index, err := locateSampleIndex(p, v)
157
-			if err != nil {
158
-				v = "ERROR: " + err.Error()
159
-			} else {
160
-				v = fmt.Sprintf("%s (%d)", p.SampleType[index].Type, index)
161
-			}
162
-		case n == "trim" || n == "compact_labels":
163
-			if o.boolValue() == true {
164
-				continue
165
-			}
166
-		case o.kind == boolKind:
167
-			if o.boolValue() == false {
168
-				continue
186
+			st := sampleTypes(p)
187
+			if v == "" {
188
+				// Apply default (last sample index).
189
+				v = st[len(st)-1]
169 190
 			}
191
+			// Add comments for all sample types in profile.
192
+			comment = "[" + strings.Join(st, " | ") + "]"
170 193
 		case n == "source_path":
171 194
 			continue
195
+		case n == "nodecount" && v == "-1":
196
+			comment = "default"
197
+		case v == "":
198
+			// Add quotes for empty values.
199
+			v = `""`
200
+		}
201
+		if comment != "" {
202
+			comment = commentStart + " " + comment
172 203
 		}
173
-		args = append(args, fmt.Sprintf("  %-25s : %s", n, v))
204
+		args = append(args, fmt.Sprintf("  %-25s = %-20s %s", n, v, comment))
205
+	}
206
+	for g, vars := range groups {
207
+		sort.Strings(vars.values)
208
+		comment := commentStart + " [" + strings.Join(vars.values, " | ") + "]"
209
+		args = append(args, fmt.Sprintf("  %-25s = %-20s %s", g, vars.set, comment))
174 210
 	}
175 211
 	sort.Strings(args)
176
-	return "Options:\n" + strings.Join(args, "\n") + "\nPPROF>"
212
+	ui.Print(strings.Join(args, "\n"))
177 213
 }
178 214
 
179 215
 // parseCommandLine parses a command and returns the pprof command to