|
@@ -24,7 +24,6 @@ import (
|
24
|
24
|
"io"
|
25
|
25
|
"os"
|
26
|
26
|
"path/filepath"
|
27
|
|
- "sort"
|
28
|
27
|
"strconv"
|
29
|
28
|
"strings"
|
30
|
29
|
|
|
@@ -95,8 +94,8 @@ func printSource(w io.Writer, rpt *Report) error {
|
95
|
94
|
fns := fileNodes[filename]
|
96
|
95
|
flatSum, cumSum := fns.Sum()
|
97
|
96
|
|
98
|
|
- fnodes, path, err := getFunctionSource(name, filename, sourcePath, fns, 0, 0)
|
99
|
|
- fmt.Fprintf(w, "ROUTINE ======================== %s in %s\n", name, path)
|
|
97
|
+ fnodes, _, err := getSourceFromFile(filename, sourcePath, fns, 0, 0)
|
|
98
|
+ fmt.Fprintf(w, "ROUTINE ======================== %s in %s\n", name, filename)
|
100
|
99
|
fmt.Fprintf(w, "%10s %10s (flat, cum) %s of Total\n",
|
101
|
100
|
rpt.formatValue(flatSum), rpt.formatValue(cumSum),
|
102
|
101
|
percentage(cumSum, rpt.total))
|
|
@@ -136,66 +135,68 @@ func printWebSource(w io.Writer, rpt *Report, obj plugin.ObjTool) error {
|
136
|
135
|
sourcePath = wd
|
137
|
136
|
}
|
138
|
137
|
|
|
138
|
+ type fileFunction struct {
|
|
139
|
+ fileName, functionName string
|
|
140
|
+ }
|
|
141
|
+
|
139
|
142
|
// Extract interesting symbols from binary files in the profile and
|
140
|
143
|
// classify samples per symbol.
|
141
|
144
|
symbols := symbolsFromBinaries(rpt.prof, g, o.Symbol, address, obj)
|
142
|
145
|
symNodes := nodesPerSymbol(g.Nodes, symbols)
|
143
|
146
|
|
144
|
|
- // Sort symbols for printing.
|
145
|
|
- var syms objSymbols
|
146
|
|
- for s := range symNodes {
|
147
|
|
- syms = append(syms, s)
|
148
|
|
- }
|
149
|
|
- sort.Sort(syms)
|
150
|
|
-
|
151
|
|
- if len(syms) == 0 {
|
152
|
|
- return fmt.Errorf("no samples found on routines matching: %s", o.Symbol.String())
|
153
|
|
- }
|
154
|
|
-
|
155
|
|
- printHeader(w, rpt)
|
156
|
|
- for _, s := range syms {
|
157
|
|
- name := s.sym.Name[0]
|
158
|
|
- // Identify sources associated to a symbol by examining
|
159
|
|
- // symbol samples. Classify samples per source file.
|
160
|
|
- var sourceFiles graph.Nodes
|
161
|
|
- fileNodes := make(map[string]graph.Nodes)
|
162
|
|
- for _, n := range symNodes[s] {
|
163
|
|
- if n.Info.File == "" {
|
|
147
|
+ // Identify sources associated to a symbol by examining
|
|
148
|
+ // symbol samples. Classify samples per source file.
|
|
149
|
+ fileNodes := make(map[fileFunction]graph.Nodes)
|
|
150
|
+ if len(symNodes) == 0 {
|
|
151
|
+ for _, n := range g.Nodes {
|
|
152
|
+ if n.Info.File == "" || !o.Symbol.MatchString(n.Info.Name) {
|
164
|
153
|
continue
|
165
|
154
|
}
|
166
|
|
- if fileNodes[n.Info.File] == nil {
|
167
|
|
- sourceFiles = append(sourceFiles, n)
|
|
155
|
+ ff := fileFunction{n.Info.File, n.Info.Name}
|
|
156
|
+ fileNodes[ff] = append(fileNodes[ff], n)
|
|
157
|
+ }
|
|
158
|
+ } else {
|
|
159
|
+ for _, nodes := range symNodes {
|
|
160
|
+ for _, n := range nodes {
|
|
161
|
+ if n.Info.File != "" {
|
|
162
|
+ ff := fileFunction{n.Info.File, n.Info.Name}
|
|
163
|
+ fileNodes[ff] = append(fileNodes[ff], n)
|
|
164
|
+ }
|
168
|
165
|
}
|
169
|
|
- fileNodes[n.Info.File] = append(fileNodes[n.Info.File], n)
|
170
|
166
|
}
|
|
167
|
+ }
|
171
|
168
|
|
172
|
|
- if len(sourceFiles) == 0 {
|
173
|
|
- fmt.Fprintf(w, "No source information for %s\n", name)
|
174
|
|
- continue
|
175
|
|
- }
|
|
169
|
+ if len(fileNodes) == 0 {
|
|
170
|
+ return fmt.Errorf("No source information for %s\n", o.Symbol.String())
|
|
171
|
+ }
|
176
|
172
|
|
177
|
|
- sourceFiles.Sort(graph.FileOrder)
|
|
173
|
+ sourceFiles := make(graph.Nodes, 0, len(fileNodes))
|
|
174
|
+ for _, nodes := range fileNodes {
|
|
175
|
+ sNode := *nodes[0]
|
|
176
|
+ sNode.Flat, sNode.Cum = nodes.Sum()
|
|
177
|
+ sourceFiles = append(sourceFiles, &sNode)
|
|
178
|
+ }
|
|
179
|
+ sourceFiles.Sort(graph.FileOrder)
|
178
|
180
|
|
179
|
|
- // Print each file associated with this function.
|
180
|
|
- for _, fl := range sourceFiles {
|
181
|
|
- filename := fl.Info.File
|
182
|
|
- fns := fileNodes[filename]
|
|
181
|
+ // Print each file associated with this function.
|
|
182
|
+ printHeader(w, rpt)
|
|
183
|
+ for _, n := range sourceFiles {
|
|
184
|
+ ff := fileFunction{n.Info.File, n.Info.Name}
|
|
185
|
+ fns := fileNodes[ff]
|
183
|
186
|
|
184
|
|
- asm := assemblyPerSourceLine(symbols, fns, filename, obj)
|
185
|
|
- start, end := sourceCoordinates(asm)
|
|
187
|
+ asm := assemblyPerSourceLine(symbols, fns, ff.fileName, obj)
|
|
188
|
+ start, end := sourceCoordinates(asm)
|
186
|
189
|
|
187
|
|
- fnodes, path, err := getFunctionSource(name, filename, sourcePath, fns, start, end)
|
188
|
|
- if err != nil {
|
189
|
|
- fnodes, path = getMissingFunctionSource(filename, asm, start, end)
|
190
|
|
- }
|
|
190
|
+ fnodes, path, err := getSourceFromFile(ff.fileName, sourcePath, fns, start, end)
|
|
191
|
+ if err != nil {
|
|
192
|
+ fnodes, path = getMissingFunctionSource(ff.fileName, asm, start, end)
|
|
193
|
+ }
|
191
|
194
|
|
192
|
|
- flatSum, cumSum := fnodes.Sum()
|
193
|
|
- printFunctionHeader(w, name, path, flatSum, cumSum, rpt)
|
194
|
|
- for _, fn := range fnodes {
|
195
|
|
- printFunctionSourceLine(w, fn, asm[fn.Info.Lineno], rpt)
|
196
|
|
- }
|
197
|
|
- printFunctionClosing(w)
|
|
195
|
+ printFunctionHeader(w, ff.functionName, path, n.Flat, n.Cum, rpt)
|
|
196
|
+ for _, fn := range fnodes {
|
|
197
|
+ printFunctionSourceLine(w, fn, asm[fn.Info.Lineno], rpt)
|
198
|
198
|
}
|
|
199
|
+ printFunctionClosing(w)
|
199
|
200
|
}
|
200
|
201
|
printPageClosing(w)
|
201
|
202
|
return nil
|
|
@@ -334,10 +335,10 @@ func printPageClosing(w io.Writer) {
|
334
|
335
|
fmt.Fprintln(w, weblistPageClosing)
|
335
|
336
|
}
|
336
|
337
|
|
337
|
|
-// getFunctionSource collects the sources of a function from a source
|
|
338
|
+// getSourceFromFile collects the sources of a function from a source
|
338
|
339
|
// file and annotates it with the samples in fns. Returns the sources
|
339
|
340
|
// as nodes, using the info.name field to hold the source code.
|
340
|
|
-func getFunctionSource(fun, file, sourcePath string, fns graph.Nodes, start, end int) (graph.Nodes, string, error) {
|
|
341
|
+func getSourceFromFile(file, sourcePath string, fns graph.Nodes, start, end int) (graph.Nodes, string, error) {
|
341
|
342
|
f, file, err := openSourceFile(file, sourcePath)
|
342
|
343
|
if err != nil {
|
343
|
344
|
return nil, file, err
|