|
@@ -55,6 +55,15 @@ func printSource(w io.Writer, rpt *Report) error {
|
55
|
55
|
}
|
56
|
56
|
functions.Sort(graph.NameOrder)
|
57
|
57
|
|
|
58
|
+ sourcePath := o.SourcePath
|
|
59
|
+ if sourcePath == "" {
|
|
60
|
+ wd, err := os.Getwd()
|
|
61
|
+ if err != nil {
|
|
62
|
+ return fmt.Errorf("Could not stat current dir: %v", err)
|
|
63
|
+ }
|
|
64
|
+ sourcePath = wd
|
|
65
|
+ }
|
|
66
|
+
|
58
|
67
|
fmt.Fprintf(w, "Total: %s\n", rpt.formatValue(rpt.total))
|
59
|
68
|
for _, fn := range functions {
|
60
|
69
|
name := fn.Info.Name
|
|
@@ -86,7 +95,7 @@ func printSource(w io.Writer, rpt *Report) error {
|
86
|
95
|
fns := fileNodes[filename]
|
87
|
96
|
flatSum, cumSum := fns.Sum()
|
88
|
97
|
|
89
|
|
- fnodes, path, err := getFunctionSource(name, filename, fns, 0, 0)
|
|
98
|
+ fnodes, path, err := getFunctionSource(name, filename, sourcePath, fns, 0, 0)
|
90
|
99
|
fmt.Fprintf(w, "ROUTINE ======================== %s in %s\n", name, path)
|
91
|
100
|
fmt.Fprintf(w, "%10s %10s (flat, cum) %s of Total\n",
|
92
|
101
|
rpt.formatValue(flatSum), rpt.formatValue(cumSum),
|
|
@@ -118,6 +127,15 @@ func printWebSource(w io.Writer, rpt *Report, obj plugin.ObjTool) error {
|
118
|
127
|
address = &hex
|
119
|
128
|
}
|
120
|
129
|
|
|
130
|
+ sourcePath := o.SourcePath
|
|
131
|
+ if sourcePath == "" {
|
|
132
|
+ wd, err := os.Getwd()
|
|
133
|
+ if err != nil {
|
|
134
|
+ return fmt.Errorf("Could not stat current dir: %v", err)
|
|
135
|
+ }
|
|
136
|
+ sourcePath = wd
|
|
137
|
+ }
|
|
138
|
+
|
121
|
139
|
// Extract interesting symbols from binary files in the profile and
|
122
|
140
|
// classify samples per symbol.
|
123
|
141
|
symbols := symbolsFromBinaries(rpt.prof, g, o.Symbol, address, obj)
|
|
@@ -166,7 +184,7 @@ func printWebSource(w io.Writer, rpt *Report, obj plugin.ObjTool) error {
|
166
|
184
|
asm := assemblyPerSourceLine(symbols, fns, filename, obj)
|
167
|
185
|
start, end := sourceCoordinates(asm)
|
168
|
186
|
|
169
|
|
- fnodes, path, err := getFunctionSource(name, filename, fns, start, end)
|
|
187
|
+ fnodes, path, err := getFunctionSource(name, filename, sourcePath, fns, start, end)
|
170
|
188
|
if err != nil {
|
171
|
189
|
fnodes, path = getMissingFunctionSource(filename, asm, start, end)
|
172
|
190
|
}
|
|
@@ -319,8 +337,8 @@ func printPageClosing(w io.Writer) {
|
319
|
337
|
// getFunctionSource collects the sources of a function from a source
|
320
|
338
|
// file and annotates it with the samples in fns. Returns the sources
|
321
|
339
|
// as nodes, using the info.name field to hold the source code.
|
322
|
|
-func getFunctionSource(fun, file string, fns graph.Nodes, start, end int) (graph.Nodes, string, error) {
|
323
|
|
- f, file, err := adjustSourcePath(file)
|
|
340
|
+func getFunctionSource(fun, file, sourcePath string, fns graph.Nodes, start, end int) (graph.Nodes, string, error) {
|
|
341
|
+ f, file, err := openSourceFile(file, sourcePath)
|
324
|
342
|
if err != nil {
|
325
|
343
|
return nil, file, err
|
326
|
344
|
}
|
|
@@ -411,31 +429,35 @@ func getMissingFunctionSource(filename string, asm map[int]graph.Nodes, start, e
|
411
|
429
|
return fnodes, filename
|
412
|
430
|
}
|
413
|
431
|
|
414
|
|
-// adjustSourcePath adjusts the path for a source file by trimmming
|
415
|
|
-// known prefixes and searching for the file on all parents of the
|
416
|
|
-// current working dir.
|
417
|
|
-func adjustSourcePath(path string) (*os.File, string, error) {
|
|
432
|
+// openSourceFile opens a source file from a name encoded in a
|
|
433
|
+// profile. File names in a profile after often relative paths, so
|
|
434
|
+// search them in each of the paths in sourcePath (or CWD by default),
|
|
435
|
+// and their parents.
|
|
436
|
+func openSourceFile(path string, sourcePath string) (*os.File, string, error) {
|
418
|
437
|
path = trimPath(path)
|
419
|
|
- f, err := os.Open(path)
|
420
|
|
- if err == nil {
|
421
|
|
- return f, path, nil
|
|
438
|
+
|
|
439
|
+ if filepath.IsAbs(path) {
|
|
440
|
+ f, err := os.Open(path)
|
|
441
|
+ return f, path, err
|
422
|
442
|
}
|
423
|
443
|
|
424
|
|
- if dir, wderr := os.Getwd(); wderr == nil {
|
|
444
|
+ // Scan each component of the path
|
|
445
|
+ for _, dir := range strings.Split(sourcePath, ":") {
|
|
446
|
+ // Search up for every parent of each possible path.
|
425
|
447
|
for {
|
|
448
|
+ filename := filepath.Join(dir, path)
|
|
449
|
+ if f, err := os.Open(filename); err == nil {
|
|
450
|
+ return f, filename, nil
|
|
451
|
+ }
|
426
|
452
|
parent := filepath.Dir(dir)
|
427
|
453
|
if parent == dir {
|
428
|
454
|
break
|
429
|
455
|
}
|
430
|
|
- if f, err := os.Open(filepath.Join(parent, path)); err == nil {
|
431
|
|
- return f, filepath.Join(parent, path), nil
|
432
|
|
- }
|
433
|
|
-
|
434
|
456
|
dir = parent
|
435
|
457
|
}
|
436
|
458
|
}
|
437
|
459
|
|
438
|
|
- return nil, path, err
|
|
460
|
+ return nil, "", fmt.Errorf("Could not find file %s on path %s", path, sourcePath)
|
439
|
461
|
}
|
440
|
462
|
|
441
|
463
|
// trimPath cleans up a path by removing prefixes that are commonly
|