Browse Source

Allow weblist to work even if assembly is not available

Weblist provides source and assembly combined in a web document.
It needs access to the binary to print the assembly, but currently
refuses to generate the source if the binary can't be find.

Fall back to just generating the source if the binary isn't found.
Raul Silvera 9 years ago
parent
commit
be8abc645f
2 changed files with 53 additions and 49 deletions
  1. 3
    0
      internal/graph/graph.go
  2. 50
    49
      internal/report/source.go

+ 3
- 0
internal/graph/graph.go View File

@@ -776,6 +776,9 @@ func (ns Nodes) Sort(o NodeOrder) error {
776 776
 				if iv, jv := l.Info.File, r.Info.File; iv != jv {
777 777
 					return iv < jv
778 778
 				}
779
+				if iv, jv := l.Info.StartLine, r.Info.StartLine; iv != jv {
780
+					return iv < jv
781
+				}
779 782
 				return compareNodes(l, r)
780 783
 			},
781 784
 		}

+ 50
- 49
internal/report/source.go View File

@@ -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