Преглед на файлове

Make '-noinlines' a separate flag, introduce '-filefunctions' granularity. (#420)

This change consists of two relatively independent parts, but they are
both about handling the granularity, so bundling them together.

First, in #415 there is a discussion that having a granularity mode by
source lines but with inlines hidden would be useful. The agreement is
also that adding `-linenoinlines` granularity would make the granularity
flags too messy (and they are already somewhat messy with `-addresses`
and `-addressnoinlines`. So, it was proposed to make `-noinlines` a
separate flag, which is what this change does. Note that the flag is now
pulled out of the granularity group so it's a bit of backward
incompatible change but I think it is acceptable. For the example in
issue #415 the user would now be able to specify `-list foo -noinlines`
to produce annotated source where the metrics from the inlined functions
are attributed to the calling inliner line.

With this change, I am also dropping the `-addressnoinlines` granularity
which is now supported as `-addresses -noinlines` combination. I
couldn't find any usage of this option at least internally at Google, so
I think it's safe to remove it.

Second, I am adding a separate `-filefunctions` granularity which groups
the data by both function and file. This is a follow-up to #110 from the
past where we changed the `-functions` granularity to not group by file
(it used to), and since then there was a couple of reports where using
just function name alone would over-aggregate the data in cases when a
function with the same name is contained in multiple source files (e.g.
see b/18874275 internally).

Also, make a number of assorted documentation and `-help` fixes.
Alexey Alexandrov преди 6 години
родител
ревизия
7dadf64105
No account linked to committer's email address

+ 15
- 15
doc/README.md Целия файл

@@ -80,21 +80,21 @@ other.
80 80
 
81 81
 Some common pprof options are:
82 82
 
83
-* **-flat [default]:** Sort entries based on their flat weight, on text reports.
84
-* **-cum:** Sort entries based on cumulative weight, on text reports.
85
-* **-functions [default]:** Accumulate samples at the function level; profile
86
-  locations that describe the same function will be merged into a report entry.
87
-* **-lines:** Accumulate samples at the source line level; profile locations that
88
-  describe the same function will be merged into a report entry.
89
-* **-addresses:** Accumulate samples at the instruction address; profile locations
90
-  that describe the same function address will be merged into a report entry.
83
+* **-flat** [default], **-cum**: Sort entries based on their flat or cumulative
84
+  weight respectively, on text reports.
85
+* **-functions** [default], **-filefunctions**, **-files**, **-lines**,
86
+  **-addresses**: Generate the report using the specified granularity.
87
+* **-noinlines**: Attribute inlined functions to their first out-of-line caller.
88
+  For example, a command like `pprof -list foo -noinlines profile.pb.gz` can be
89
+  used to produce the annotated source listing attributing the metrics in the
90
+  inlined functions to the out-of-line calling line.
91 91
 * **-nodecount= _int_:** Maximum number of entries in the report. pprof will only print
92 92
   this many entries and will use heuristics to select which entries to trim.
93 93
 * **-focus= _regex_:** Only include samples that include a report entry matching
94 94
   *regex*.
95 95
 * **-ignore= _regex_:** Do not include samples that include a report entry matching
96 96
   *regex*.
97
-* **-show\_from= _regex_:** Do not show entries above the first one that 
97
+* **-show\_from= _regex_:** Do not show entries above the first one that
98 98
   matches *regex*.
99 99
 * **-show= _regex_:** Only show entries that match *regex*.
100 100
 * **-hide= _regex_:** Do not show entries that match *regex*.
@@ -209,12 +209,12 @@ default it will search for those tools in the current path, but it can also
209 209
 search for them in a directory pointed to by the environment variable
210 210
 `$PPROF_TOOLS`.
211 211
 
212
-* **-disasm= _regex_:** Generates an annotated source listing for functions matching
213
-  regex, with flat/cum weights for each source line.
214
-* **-list= _regex_:** Generates an annotated disassembly listing for functions
215
-  matching *regex*.
216
-* **-weblist= _regex_:** Generates a source/assembly combined annotated listing for
217
-  functions matching *regex*, and starts a web browser to display it.
212
+* **-list= _regex_:** Generates an annotated source listing for functions
213
+  matching *regex*, with flat/cum weights for each source line.
214
+* **-disasm= _regex_:** Generates an annotated disassembly listing for
215
+  functions matching *regex*.
216
+* **-weblist= _regex_:** Generates a source/assembly combined annotated listing
217
+  for functions matching *regex*, and starts a web browser to display it.
218 218
 
219 219
 ## Comparing profiles
220 220
 

+ 7
- 7
internal/driver/commands.go Целия файл

@@ -228,17 +228,17 @@ var pprofVariables = variables{
228 228
 	// Output granularity
229 229
 	"functions": &variable{boolKind, "t", "granularity", helpText(
230 230
 		"Aggregate at the function level.",
231
-		"Takes into account the filename/lineno where the function was defined.")},
231
+		"Ignores the filename where the function was defined.")},
232
+	"filefunctions": &variable{boolKind, "t", "granularity", helpText(
233
+		"Aggregate at the function level.",
234
+		"Takes into account the filename where the function was defined.")},
232 235
 	"files": &variable{boolKind, "f", "granularity", "Aggregate at the file level."},
233 236
 	"lines": &variable{boolKind, "f", "granularity", "Aggregate at the source code line level."},
234 237
 	"addresses": &variable{boolKind, "f", "granularity", helpText(
235
-		"Aggregate at the function level.",
238
+		"Aggregate at the address level.",
236 239
 		"Includes functions' addresses in the output.")},
237
-	"noinlines": &variable{boolKind, "f", "granularity", helpText(
238
-		"Aggregate at the function level.",
239
-		"Attributes inlined functions to their first out-of-line caller.")},
240
-	"addressnoinlines": &variable{boolKind, "f", "granularity", helpText(
241
-		"Aggregate at the function level, including functions' addresses in the output.",
240
+	"noinlines": &variable{boolKind, "f", "", helpText(
241
+		"Ignore inlines.",
242 242
 		"Attributes inlined functions to their first out-of-line caller.")},
243 243
 }
244 244
 

+ 26
- 16
internal/driver/driver.go Целия файл

@@ -152,20 +152,28 @@ func generateReport(p *profile.Profile, cmd []string, vars variables, o *plugin.
152 152
 }
153 153
 
154 154
 func applyCommandOverrides(cmd string, outputFormat int, v variables) variables {
155
+	// Some report types override the trim flag to false below. This is to make
156
+	// sure the default heuristics of excluding insignificant nodes and edges
157
+	// from the call graph do not apply. One example where it is important is
158
+	// annotated source or disassembly listing. Those reports run on a specific
159
+	// function (or functions), but the trimming is applied before the function
160
+	// data is selected. So, with trimming enabled, the report could end up
161
+	// showing no data if the specified function is "uninteresting" as far as the
162
+	// trimming is concerned.
155 163
 	trim := v["trim"].boolValue()
156 164
 
157 165
 	switch cmd {
158
-	case "callgrind", "kcachegrind":
159
-		trim = false
160
-		v.set("addresses", "t")
161 166
 	case "disasm", "weblist":
162 167
 		trim = false
163
-		v.set("addressnoinlines", "t")
168
+		v.set("addresses", "t")
169
+		v.set("noinlines", "t")
164 170
 	case "peek":
165 171
 		trim = false
166 172
 	case "list":
167
-		v.set("nodecount", "0")
173
+		trim = false
168 174
 		v.set("lines", "t")
175
+		// Do not force 'noinlines' to be false so that specifying
176
+		// "-list foo -noinlines" is supported and works as expected.
169 177
 	case "text", "top", "topproto":
170 178
 		if v["nodecount"].intValue() == -1 {
171 179
 			v.set("nodecount", "0")
@@ -176,9 +184,11 @@ func applyCommandOverrides(cmd string, outputFormat int, v variables) variables
176 184
 		}
177 185
 	}
178 186
 
179
-	if outputFormat == report.Proto || outputFormat == report.Raw {
187
+	switch outputFormat {
188
+	case report.Proto, report.Raw, report.Callgrind:
180 189
 		trim = false
181 190
 		v.set("addresses", "t")
191
+		v.set("noinlines", "f")
182 192
 	}
183 193
 
184 194
 	if !trim {
@@ -190,28 +200,28 @@ func applyCommandOverrides(cmd string, outputFormat int, v variables) variables
190 200
 }
191 201
 
192 202
 func aggregate(prof *profile.Profile, v variables) error {
193
-	var inlines, function, filename, linenumber, address bool
203
+	var function, filename, linenumber, address bool
204
+	inlines := !v["noinlines"].boolValue()
194 205
 	switch {
195 206
 	case v["addresses"].boolValue():
196
-		return nil
207
+		if inlines {
208
+			return nil
209
+		}
210
+		function = true
211
+		filename = true
212
+		linenumber = true
213
+		address = true
197 214
 	case v["lines"].boolValue():
198
-		inlines = true
199 215
 		function = true
200 216
 		filename = true
201 217
 		linenumber = true
202 218
 	case v["files"].boolValue():
203
-		inlines = true
204 219
 		filename = true
205 220
 	case v["functions"].boolValue():
206
-		inlines = true
207 221
 		function = true
208
-	case v["noinlines"].boolValue():
209
-		function = true
210
-	case v["addressnoinlines"].boolValue():
222
+	case v["filefunctions"].boolValue():
211 223
 		function = true
212 224
 		filename = true
213
-		linenumber = true
214
-		address = true
215 225
 	default:
216 226
 		return fmt.Errorf("unexpected granularity")
217 227
 	}

+ 5
- 1
internal/driver/driver_test.go Целия файл

@@ -53,6 +53,9 @@ func TestParse(t *testing.T) {
53 53
 		flags, source string
54 54
 	}{
55 55
 		{"text,functions,flat", "cpu"},
56
+		{"text,functions,noinlines,flat", "cpu"},
57
+		{"text,filefunctions,noinlines,flat", "cpu"},
58
+		{"text,addresses,noinlines,flat", "cpu"},
56 59
 		{"tree,addresses,flat,nodecount=4", "cpusmall"},
57 60
 		{"text,functions,flat,nodecount=5,call_tree", "unknown"},
58 61
 		{"text,alloc_objects,flat", "heap_alloc"},
@@ -248,7 +251,8 @@ func testSourceURL(port int) string {
248 251
 func solutionFilename(source string, f *testFlags) string {
249 252
 	name := []string{"pprof", strings.TrimPrefix(source, testSourceURL(8000))}
250 253
 	name = addString(name, f, []string{"flat", "cum"})
251
-	name = addString(name, f, []string{"functions", "files", "lines", "addresses"})
254
+	name = addString(name, f, []string{"functions", "filefunctions", "files", "lines", "addresses"})
255
+	name = addString(name, f, []string{"noinlines"})
252 256
 	name = addString(name, f, []string{"inuse_space", "inuse_objects", "alloc_space", "alloc_objects"})
253 257
 	name = addString(name, f, []string{"relative_percentages"})
254 258
 	name = addString(name, f, []string{"seconds"})

+ 7
- 6
internal/driver/interactive_test.go Целия файл

@@ -259,12 +259,13 @@ func TestInteractiveCommands(t *testing.T) {
259 259
 		{
260 260
 			"weblist  find -test",
261 261
 			map[string]string{
262
-				"functions":        "false",
263
-				"addressnoinlines": "true",
264
-				"nodecount":        "0",
265
-				"cum":              "false",
266
-				"flat":             "true",
267
-				"ignore":           "test",
262
+				"functions": "false",
263
+				"addresses": "true",
264
+				"noinlines": "true",
265
+				"nodecount": "0",
266
+				"cum":       "false",
267
+				"flat":      "true",
268
+				"ignore":    "test",
268 269
 			},
269 270
 		},
270 271
 		{

+ 7
- 0
internal/driver/testdata/pprof.cpu.flat.addresses.noinlines.text Целия файл

@@ -0,0 +1,7 @@
1
+Showing nodes accounting for 1.12s, 100% of 1.12s total
2
+Dropped 1 node (cum <= 0.06s)
3
+      flat  flat%   sum%        cum   cum%
4
+     1.10s 98.21% 98.21%      1.10s 98.21%  0000000000001000 line1000 testdata/file1000.src:1
5
+     0.01s  0.89% 99.11%      1.01s 90.18%  0000000000002000 line2000 testdata/file2000.src:4
6
+     0.01s  0.89%   100%      1.01s 90.18%  0000000000003000 line3000 testdata/file3000.src:6
7
+         0     0%   100%      0.10s  8.93%  0000000000003001 line3000 testdata/file3000.src:9

+ 5
- 0
internal/driver/testdata/pprof.cpu.flat.filefunctions.noinlines.text Целия файл

@@ -0,0 +1,5 @@
1
+Showing nodes accounting for 1.12s, 100% of 1.12s total
2
+      flat  flat%   sum%        cum   cum%
3
+     1.10s 98.21% 98.21%      1.10s 98.21%  line1000 testdata/file1000.src
4
+     0.01s  0.89% 99.11%      1.01s 90.18%  line2000 testdata/file2000.src
5
+     0.01s  0.89%   100%      1.12s   100%  line3000 testdata/file3000.src

+ 5
- 0
internal/driver/testdata/pprof.cpu.flat.functions.noinlines.text Целия файл

@@ -0,0 +1,5 @@
1
+Showing nodes accounting for 1.12s, 100% of 1.12s total
2
+      flat  flat%   sum%        cum   cum%
3
+     1.10s 98.21% 98.21%      1.10s 98.21%  line1000
4
+     0.01s  0.89% 99.11%      1.01s 90.18%  line2000
5
+     0.01s  0.89%   100%      1.12s   100%  line3000