aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/vendor/github.com/google
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/vendor/github.com/google')
-rw-r--r--src/cmd/vendor/github.com/google/pprof/driver/driver.go2
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go6
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go22
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go2
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/html/graph.css7
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/html/graph.html1
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/html/source.html70
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/html/stacks.html1
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/html/stacks.js60
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/settings.go2
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/stacks.go6
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go20
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/webui.go32
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go7
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/graph/graph.go2
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/measurement/measurement.go61
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go2
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/report/report.go8
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/report/source.go223
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go4
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/symbolizer/symbolizer.go177
-rw-r--r--src/cmd/vendor/github.com/google/pprof/profile/profile.go2
22 files changed, 390 insertions, 327 deletions
diff --git a/src/cmd/vendor/github.com/google/pprof/driver/driver.go b/src/cmd/vendor/github.com/google/pprof/driver/driver.go
index d5860036c3..6cbf66939d 100644
--- a/src/cmd/vendor/github.com/google/pprof/driver/driver.go
+++ b/src/cmd/vendor/github.com/google/pprof/driver/driver.go
@@ -202,7 +202,7 @@ type Sym struct {
// A UI manages user interactions.
type UI interface {
- // Read returns a line of text (a command) read from the user.
+ // ReadLine returns a line of text (a command) read from the user.
// prompt is printed before reading the command.
ReadLine(prompt string) (string, error)
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go
index efa9167af7..ed87b7e6f8 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go
@@ -433,10 +433,8 @@ func (b *binrep) openELF(name string, start, limit, offset uint64, relocationSym
defer ef.Close()
buildID := ""
- if f, err := os.Open(name); err == nil {
- if id, err := elfexec.GetBuildID(f); err == nil {
- buildID = fmt.Sprintf("%x", id)
- }
+ if id, err := elfexec.GetBuildID(ef); err == nil {
+ buildID = fmt.Sprintf("%x", id)
}
var (
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go
index 74ce8cb422..18941926c5 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go
@@ -20,6 +20,7 @@ package driver
import (
"bytes"
"fmt"
+ "io"
"os"
"path/filepath"
"regexp"
@@ -118,7 +119,14 @@ func generateReport(p *profile.Profile, cmd []string, cfg config, o *plugin.Opti
// Generate the report.
dst := new(bytes.Buffer)
- if err := report.Generate(dst, rpt, o.Obj); err != nil {
+ switch rpt.OutputFormat() {
+ case report.WebList:
+ // We need template expansion, so generate here instead of in report.
+ err = printWebList(dst, rpt, o.Obj)
+ default:
+ err = report.Generate(dst, rpt, o.Obj)
+ }
+ if err != nil {
return err
}
src := dst
@@ -155,6 +163,18 @@ func generateReport(p *profile.Profile, cmd []string, cfg config, o *plugin.Opti
return out.Close()
}
+func printWebList(dst io.Writer, rpt *report.Report, obj plugin.ObjTool) error {
+ listing, err := report.MakeWebList(rpt, obj, -1)
+ if err != nil {
+ return err
+ }
+ legend := report.ProfileLabels(rpt)
+ return renderHTML(dst, "sourcelisting", rpt, nil, legend, webArgs{
+ Standalone: true,
+ Listing: listing,
+ })
+}
+
func applyCommandOverrides(cmd string, outputFormat int, cfg config) config {
// Some report types override the trim flag to false below. This is to make
// sure the default heuristics of excluding insignificant nodes and edges
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go
index 95204a394f..a94ddf6adb 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go
@@ -493,7 +493,7 @@ func fetch(source string, duration, timeout time.Duration, ui plugin.UI, tr http
var f io.ReadCloser
// First determine whether the source is a file, if not, it will be treated as a URL.
- if _, openErr := os.Stat(source); openErr == nil {
+ if _, err = os.Stat(source); err == nil {
if isPerfFile(source) {
f, err = convertPerfData(source, ui)
} else {
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/html/graph.css b/src/cmd/vendor/github.com/google/pprof/internal/driver/html/graph.css
new file mode 100644
index 0000000000..c756ddfdcb
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/html/graph.css
@@ -0,0 +1,7 @@
+#graph {
+ cursor: grab;
+}
+
+#graph:active {
+ cursor: grabbing;
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/html/graph.html b/src/cmd/vendor/github.com/google/pprof/internal/driver/html/graph.html
index a113549fc4..d17a0ea7d0 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/html/graph.html
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/html/graph.html
@@ -4,6 +4,7 @@
<meta charset="utf-8">
<title>{{.Title}}</title>
{{template "css" .}}
+ {{template "graph_css" .}}
</head>
<body>
{{template "header" .}}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/html/source.html b/src/cmd/vendor/github.com/google/pprof/internal/driver/html/source.html
index 3212bee4a0..b676ce2054 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/html/source.html
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/html/source.html
@@ -3,16 +3,70 @@
<head>
<meta charset="utf-8">
<title>{{.Title}}</title>
- {{template "css" .}}
+ {{if not .Standalone}}{{template "css" .}}{{end}}
{{template "weblistcss" .}}
{{template "weblistjs" .}}
</head>
-<body>
- {{template "header" .}}
- <div id="content" class="source">
- {{.HTMLBody}}
- </div>
- {{template "script" .}}
- <script>viewer(new URL(window.location.href), null);</script>
+<body>{{"\n" -}}
+ {{/* emit different header in standalone mode */ -}}
+ {{if .Standalone}}{{"\n" -}}
+ <div class="legend">{{"" -}}
+ {{range $i, $e := .Legend -}}
+ {{if $i}}<br>{{"\n"}}{{end}}{{. -}}
+ {{end}}<br>Total: {{.Listing.Total -}}
+ </div>{{"" -}}
+ {{else -}}
+ {{template "header" .}}
+ <div id="content" class="source">{{"" -}}
+ {{end -}}
+
+ {{range .Listing.Files -}}
+ {{range .Funcs -}}
+ <h2>{{.Name}}</h2>{{"" -}}
+ <p class="filename">{{.File}}</p>{{"\n" -}}
+ <pre onClick="pprof_toggle_asm(event)">{{"\n" -}}
+ {{printf " Total: %10s %10s (flat, cum) %s" .Flat .Cumulative .Percent -}}
+ {{range .Lines -}}{{"\n" -}}
+ {{/* source line */ -}}
+ <span class=line>{{printf " %6d" .Line}}</span>{{" " -}}
+ <span class={{.HTMLClass}}>
+ {{- printf " %10s %10s %8s %s " .Flat .Cumulative "" .SrcLine -}}
+ </span>{{"" -}}
+
+ {{if .Instructions -}}
+ {{/* instructions for this source line */ -}}
+ <span class=asm>{{"" -}}
+ {{range .Instructions -}}
+ {{/* separate when we hit a new basic block */ -}}
+ {{if .NewBlock -}}{{printf " %8s %28s\n" "" "⋮"}}{{end -}}
+
+ {{/* inlined calls leading to this instruction */ -}}
+ {{range .InlinedCalls -}}
+ {{printf " %8s %10s %10s %8s " "" "" "" "" -}}
+ <span class=inlinesrc>{{.SrcLine}}</span>{{" " -}}
+ <span class=unimportant>{{.FileBase}}:{{.Line}}</span>{{"\n" -}}
+ {{end -}}
+
+ {{if not .Synthetic -}}
+ {{/* disassembled instruction */ -}}
+ {{printf " %8s %10s %10s %8x: %s " "" .Flat .Cumulative .Address .Disasm -}}
+ <span class=unimportant>{{.FileLine}}</span>{{"\n" -}}
+ {{end -}}
+ {{end -}}
+ </span>{{"" -}}
+ {{end -}}
+ {{/* end of line */ -}}
+ {{end}}{{"\n" -}}
+ </pre>{{"\n" -}}
+ {{/* end of function */ -}}
+ {{end -}}
+ {{/* end of file */ -}}
+ {{end -}}
+
+ {{if not .Standalone}}{{"\n " -}}
+ </div>{{"\n" -}}
+ {{template "script" .}}{{"\n" -}}
+ <script>viewer(new URL(window.location.href), null);</script>{{"" -}}
+ {{end}}
</body>
</html>
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/html/stacks.html b/src/cmd/vendor/github.com/google/pprof/internal/driver/html/stacks.html
index 1ddb7a3a1c..c2f8cf26b1 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/html/stacks.html
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/html/stacks.html
@@ -26,6 +26,7 @@
{{template "script" .}}
{{template "stacks_js"}}
<script>
+ pprofUnitDefs = {{.UnitDefs}};
stackViewer({{.Stacks}}, {{.Nodes}});
</script>
</body>
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/html/stacks.js b/src/cmd/vendor/github.com/google/pprof/internal/driver/html/stacks.js
index c8059fe6bf..df0f0649b9 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/html/stacks.js
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/html/stacks.js
@@ -13,23 +13,6 @@ function stackViewer(stacks, nodes) {
const FONT_SIZE = 12;
const MIN_FONT_SIZE = 8;
- // Mapping from unit to a list of display scales/labels.
- // List should be ordered by increasing unit size.
- const UNITS = new Map([
- ['B', [
- ['B', 1],
- ['kB', Math.pow(2, 10)],
- ['MB', Math.pow(2, 20)],
- ['GB', Math.pow(2, 30)],
- ['TB', Math.pow(2, 40)],
- ['PB', Math.pow(2, 50)]]],
- ['s', [
- ['ns', 1e-9],
- ['µs', 1e-6],
- ['ms', 1e-3],
- ['s', 1],
- ['hrs', 60*60]]]]);
-
// Fields
let pivots = []; // Indices of currently selected data.Sources entries.
let matches = new Set(); // Indices of sources that match search
@@ -570,22 +553,7 @@ function stackViewer(stacks, nodes) {
// unitText returns a formatted string to display for value.
function unitText(value) {
- const sign = (value < 0) ? "-" : "";
- let v = Math.abs(value) * stacks.Scale;
- // Rescale to appropriate display unit.
- let unit = stacks.Unit;
- const list = UNITS.get(unit);
- if (list) {
- // Find first entry in list that is not too small.
- for (const [name, scale] of list) {
- if (v <= 100*scale) {
- v /= scale;
- unit = name;
- break;
- }
- }
- }
- return sign + Number(v.toFixed(2)) + unit;
+ return pprofUnitText(value*stacks.Scale, stacks.Unit);
}
function find(name) {
@@ -606,3 +574,29 @@ function stackViewer(stacks, nodes) {
return hsl;
}
}
+
+// pprofUnitText returns a formatted string to display for value in the specified unit.
+function pprofUnitText(value, unit) {
+ const sign = (value < 0) ? "-" : "";
+ let v = Math.abs(value);
+ // Rescale to appropriate display unit.
+ let list = null;
+ for (const def of pprofUnitDefs) {
+ if (def.DefaultUnit.CanonicalName == unit) {
+ list = def.Units;
+ v *= def.DefaultUnit.Factor;
+ break;
+ }
+ }
+ if (list) {
+ // Stop just before entry that is too large.
+ for (let i = 0; i < list.length; i++) {
+ if (i == list.length-1 || list[i+1].Factor > v) {
+ v /= list[i].Factor;
+ unit = list[i].CanonicalName;
+ break;
+ }
+ }
+ }
+ return sign + Number(v.toFixed(2)) + unit;
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/settings.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/settings.go
index b784618aca..5011a06666 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/settings.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/settings.go
@@ -102,7 +102,7 @@ func configMenu(fname string, u url.URL) []configMenuEntry {
UserConfig: (i != 0),
}
}
- // Mark the last matching config as currennt
+ // Mark the last matching config as current
if lastMatch >= 0 {
result[lastMatch].Current = true
}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/stacks.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/stacks.go
index 6a61613344..355b8f2e2a 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/stacks.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/stacks.go
@@ -19,6 +19,7 @@ import (
"html/template"
"net/http"
+ "github.com/google/pprof/internal/measurement"
"github.com/google/pprof/internal/report"
)
@@ -52,7 +53,8 @@ func (ui *webInterface) stackView(w http.ResponseWriter, req *http.Request) {
_, legend := report.TextItems(rpt)
ui.render(w, req, "stacks", rpt, errList, legend, webArgs{
- Stacks: template.JS(b),
- Nodes: nodes,
+ Stacks: template.JS(b),
+ Nodes: nodes,
+ UnitDefs: measurement.UnitTypes,
})
}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go
index 984936a9d6..0b8630bcf1 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go
@@ -19,8 +19,27 @@ import (
"fmt"
"html/template"
"os"
+ "sync"
+
+ "github.com/google/pprof/internal/report"
+)
+
+var (
+ htmlTemplates *template.Template // Lazily loaded templates
+ htmlTemplateInit sync.Once
)
+// getHTMLTemplates returns the set of HTML templates used by pprof,
+// initializing them if necessary.
+func getHTMLTemplates() *template.Template {
+ htmlTemplateInit.Do(func() {
+ htmlTemplates = template.New("templategroup")
+ addTemplates(htmlTemplates)
+ report.AddSourceTemplates(htmlTemplates)
+ })
+ return htmlTemplates
+}
+
//go:embed html
var embeddedFiles embed.FS
@@ -54,6 +73,7 @@ func addTemplates(templates *template.Template) {
def("css", loadCSS("html/common.css"))
def("header", loadFile("html/header.html"))
def("graph", loadFile("html/graph.html"))
+ def("graph_css", loadCSS("html/graph.css"))
def("script", loadJS("html/common.js"))
def("top", loadFile("html/top.html"))
def("sourcelisting", loadFile("html/source.html"))
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/webui.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/webui.go
index 476e1d2cdf..2a2d7fb1d2 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/webui.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/webui.go
@@ -18,6 +18,7 @@ import (
"bytes"
"fmt"
"html/template"
+ "io"
"net"
"net/http"
gourl "net/url"
@@ -28,6 +29,7 @@ import (
"time"
"github.com/google/pprof/internal/graph"
+ "github.com/google/pprof/internal/measurement"
"github.com/google/pprof/internal/plugin"
"github.com/google/pprof/internal/report"
"github.com/google/pprof/profile"
@@ -39,7 +41,6 @@ type webInterface struct {
copier profileCopier
options *plugin.Options
help map[string]string
- templates *template.Template
settingsFile string
}
@@ -48,15 +49,11 @@ func makeWebInterface(p *profile.Profile, copier profileCopier, opt *plugin.Opti
if err != nil {
return nil, err
}
- templates := template.New("templategroup")
- addTemplates(templates)
- report.AddSourceTemplates(templates)
return &webInterface{
prof: p,
copier: copier,
options: opt,
help: make(map[string]string),
- templates: templates,
settingsFile: settingsFile,
}, nil
}
@@ -82,14 +79,17 @@ type webArgs struct {
Total int64
SampleTypes []string
Legend []string
+ Standalone bool // True for command-line generation of HTML
Help map[string]string
Nodes []string
HTMLBody template.HTML
TextBody string
Top []report.TextItem
+ Listing report.WebListData
FlameGraph template.JS
Stacks template.JS
Configs []configMenuEntry
+ UnitDefs []measurement.UnitType
}
func serveWebInterface(hostport string, p *profile.Profile, o *plugin.Options, disableBrowser bool) error {
@@ -283,21 +283,25 @@ func (ui *webInterface) makeReport(w http.ResponseWriter, req *http.Request,
return rpt, catcher.errors
}
-// render generates html using the named template based on the contents of data.
-func (ui *webInterface) render(w http.ResponseWriter, req *http.Request, tmpl string,
- rpt *report.Report, errList, legend []string, data webArgs) {
+// renderHTML generates html using the named template based on the contents of data.
+func renderHTML(dst io.Writer, tmpl string, rpt *report.Report, errList, legend []string, data webArgs) error {
file := getFromLegend(legend, "File: ", "unknown")
profile := getFromLegend(legend, "Type: ", "unknown")
data.Title = file + " " + profile
data.Errors = errList
data.Total = rpt.Total()
- data.SampleTypes = sampleTypes(ui.prof)
data.Legend = legend
+ return getHTMLTemplates().ExecuteTemplate(dst, tmpl, data)
+}
+
+// render responds with html generated by passing data to the named template.
+func (ui *webInterface) render(w http.ResponseWriter, req *http.Request, tmpl string,
+ rpt *report.Report, errList, legend []string, data webArgs) {
+ data.SampleTypes = sampleTypes(ui.prof)
data.Help = ui.help
data.Configs = configMenu(ui.settingsFile, *req.URL)
-
html := &bytes.Buffer{}
- if err := ui.templates.ExecuteTemplate(html, tmpl, data); err != nil {
+ if err := renderHTML(html, tmpl, rpt, errList, legend, data); err != nil {
http.Error(w, "internal template error", http.StatusInternalServerError)
ui.options.UI.PrintErr(err)
return
@@ -410,8 +414,8 @@ func (ui *webInterface) source(w http.ResponseWriter, req *http.Request) {
}
// Generate source listing.
- var body bytes.Buffer
- if err := report.PrintWebList(&body, rpt, ui.options.Obj, maxEntries); err != nil {
+ listing, err := report.MakeWebList(rpt, ui.options.Obj, maxEntries)
+ if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
ui.options.UI.PrintErr(err)
return
@@ -419,7 +423,7 @@ func (ui *webInterface) source(w http.ResponseWriter, req *http.Request) {
legend := report.ProfileLabels(rpt)
ui.render(w, req, "sourcelisting", rpt, errList, legend, webArgs{
- HTMLBody: template.HTML(body.String()),
+ Listing: listing,
})
}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go b/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go
index 718481b078..10436a2256 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go
@@ -118,12 +118,7 @@ func parseNotes(reader io.Reader, alignment int, order binary.ByteOrder) ([]elfN
//
// If no build-ID was found but the binary was read without error, it returns
// (nil, nil).
-func GetBuildID(binary io.ReaderAt) ([]byte, error) {
- f, err := elf.NewFile(binary)
- if err != nil {
- return nil, err
- }
-
+func GetBuildID(f *elf.File) ([]byte, error) {
findBuildID := func(notes []elfNote) ([]byte, error) {
var buildID []byte
for _, note := range notes {
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/graph/graph.go b/src/cmd/vendor/github.com/google/pprof/internal/graph/graph.go
index 5ad10a2ae0..8abbd83f76 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/graph/graph.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/graph/graph.go
@@ -444,7 +444,7 @@ func newTree(prof *profile.Profile, o *Options) (g *Graph) {
}
}
- nodes := make(Nodes, len(prof.Location))
+ nodes := make(Nodes, 0, len(prof.Location))
for _, nm := range parentNodeMap {
nodes = append(nodes, nm.nodes()...)
}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/measurement/measurement.go b/src/cmd/vendor/github.com/google/pprof/internal/measurement/measurement.go
index d9644f9326..e5b7dbc6c4 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/measurement/measurement.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/measurement/measurement.go
@@ -113,7 +113,7 @@ func compatibleValueTypes(v1, v2 *profile.ValueType) bool {
if v1.Unit == v2.Unit {
return true
}
- for _, ut := range unitTypes {
+ for _, ut := range UnitTypes {
if ut.sniffUnit(v1.Unit) != nil && ut.sniffUnit(v2.Unit) != nil {
return true
}
@@ -130,7 +130,7 @@ func Scale(value int64, fromUnit, toUnit string) (float64, string) {
v, u := Scale(-value, fromUnit, toUnit)
return -v, u
}
- for _, ut := range unitTypes {
+ for _, ut := range UnitTypes {
if v, u, ok := ut.convertUnit(value, fromUnit, toUnit); ok {
return v, u
}
@@ -177,26 +177,26 @@ func Percentage(value, total int64) string {
}
}
-// unit includes a list of aliases representing a specific unit and a factor
+// Unit includes a list of aliases representing a specific unit and a factor
// which one can multiple a value in the specified unit by to get the value
// in terms of the base unit.
-type unit struct {
- canonicalName string
+type Unit struct {
+ CanonicalName string
aliases []string
- factor float64
+ Factor float64
}
-// unitType includes a list of units that are within the same category (i.e.
+// UnitType includes a list of units that are within the same category (i.e.
// memory or time units) and a default unit to use for this type of unit.
-type unitType struct {
- defaultUnit unit
- units []unit
+type UnitType struct {
+ DefaultUnit Unit
+ Units []Unit
}
// findByAlias returns the unit associated with the specified alias. It returns
// nil if the unit with such alias is not found.
-func (ut unitType) findByAlias(alias string) *unit {
- for _, u := range ut.units {
+func (ut UnitType) findByAlias(alias string) *Unit {
+ for _, u := range ut.Units {
for _, a := range u.aliases {
if alias == a {
return &u
@@ -208,7 +208,7 @@ func (ut unitType) findByAlias(alias string) *unit {
// sniffUnit simpifies the input alias and returns the unit associated with the
// specified alias. It returns nil if the unit with such alias is not found.
-func (ut unitType) sniffUnit(unit string) *unit {
+func (ut UnitType) sniffUnit(unit string) *Unit {
unit = strings.ToLower(unit)
if len(unit) > 2 {
unit = strings.TrimSuffix(unit, "s")
@@ -219,13 +219,13 @@ func (ut unitType) sniffUnit(unit string) *unit {
// autoScale takes in the value with units of the base unit and returns
// that value scaled to a reasonable unit if a reasonable unit is
// found.
-func (ut unitType) autoScale(value float64) (float64, string, bool) {
+func (ut UnitType) autoScale(value float64) (float64, string, bool) {
var f float64
var unit string
- for _, u := range ut.units {
- if u.factor >= f && (value/u.factor) >= 1.0 {
- f = u.factor
- unit = u.canonicalName
+ for _, u := range ut.Units {
+ if u.Factor >= f && (value/u.Factor) >= 1.0 {
+ f = u.Factor
+ unit = u.CanonicalName
}
}
if f == 0 {
@@ -239,27 +239,28 @@ func (ut unitType) autoScale(value float64) (float64, string, bool) {
// included in the unitType, then a false boolean will be returned. If the
// toUnit is not in the unitType, the value will be returned in terms of the
// default unitType.
-func (ut unitType) convertUnit(value int64, fromUnitStr, toUnitStr string) (float64, string, bool) {
+func (ut UnitType) convertUnit(value int64, fromUnitStr, toUnitStr string) (float64, string, bool) {
fromUnit := ut.sniffUnit(fromUnitStr)
if fromUnit == nil {
return 0, "", false
}
- v := float64(value) * fromUnit.factor
+ v := float64(value) * fromUnit.Factor
if toUnitStr == "minimum" || toUnitStr == "auto" {
if v, u, ok := ut.autoScale(v); ok {
return v, u, true
}
- return v / ut.defaultUnit.factor, ut.defaultUnit.canonicalName, true
+ return v / ut.DefaultUnit.Factor, ut.DefaultUnit.CanonicalName, true
}
toUnit := ut.sniffUnit(toUnitStr)
if toUnit == nil {
- return v / ut.defaultUnit.factor, ut.defaultUnit.canonicalName, true
+ return v / ut.DefaultUnit.Factor, ut.DefaultUnit.CanonicalName, true
}
- return v / toUnit.factor, toUnit.canonicalName, true
+ return v / toUnit.Factor, toUnit.CanonicalName, true
}
-var unitTypes = []unitType{{
- units: []unit{
+// UnitTypes holds the definition of units known to pprof.
+var UnitTypes = []UnitType{{
+ Units: []Unit{
{"B", []string{"b", "byte"}, 1},
{"kB", []string{"kb", "kbyte", "kilobyte"}, float64(1 << 10)},
{"MB", []string{"mb", "mbyte", "megabyte"}, float64(1 << 20)},
@@ -267,18 +268,18 @@ var unitTypes = []unitType{{
{"TB", []string{"tb", "tbyte", "terabyte"}, float64(1 << 40)},
{"PB", []string{"pb", "pbyte", "petabyte"}, float64(1 << 50)},
},
- defaultUnit: unit{"B", []string{"b", "byte"}, 1},
+ DefaultUnit: Unit{"B", []string{"b", "byte"}, 1},
}, {
- units: []unit{
+ Units: []Unit{
{"ns", []string{"ns", "nanosecond"}, float64(time.Nanosecond)},
{"us", []string{"μs", "us", "microsecond"}, float64(time.Microsecond)},
{"ms", []string{"ms", "millisecond"}, float64(time.Millisecond)},
{"s", []string{"s", "sec", "second"}, float64(time.Second)},
{"hrs", []string{"hour", "hr"}, float64(time.Hour)},
},
- defaultUnit: unit{"s", []string{}, float64(time.Second)},
+ DefaultUnit: Unit{"s", []string{}, float64(time.Second)},
}, {
- units: []unit{
+ Units: []Unit{
{"n*GCU", []string{"nanogcu"}, 1e-9},
{"u*GCU", []string{"microgcu"}, 1e-6},
{"m*GCU", []string{"milligcu"}, 1e-3},
@@ -289,5 +290,5 @@ var unitTypes = []unitType{{
{"T*GCU", []string{"teragcu"}, 1e12},
{"P*GCU", []string{"petagcu"}, 1e15},
},
- defaultUnit: unit{"GCU", []string{}, 1.0},
+ DefaultUnit: Unit{"GCU", []string{}, 1.0},
}}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go b/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go
index c934551036..f2ef987185 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/plugin/plugin.go
@@ -175,7 +175,7 @@ type Sym struct {
// A UI manages user interactions.
type UI interface {
- // Read returns a line of text (a command) read from the user.
+ // ReadLine returns a line of text (a command) read from the user.
// prompt is printed before reading the command.
ReadLine(prompt string) (string, error)
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/report.go b/src/cmd/vendor/github.com/google/pprof/internal/report/report.go
index 96b80039e6..d72ebe914f 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/report/report.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/report/report.go
@@ -111,12 +111,11 @@ func Generate(w io.Writer, rpt *Report, obj plugin.ObjTool) error {
return printAssembly(w, rpt, obj)
case List:
return printSource(w, rpt)
- case WebList:
- return printWebSource(w, rpt, obj)
case Callgrind:
return printCallgrind(w, rpt)
}
- return fmt.Errorf("unexpected output format")
+ // Note: WebList handling is in driver package.
+ return fmt.Errorf("unexpected output format %v", o.OutputFormat)
}
// newTrimmedGraph creates a graph for this report, trimmed according
@@ -1327,6 +1326,9 @@ type Report struct {
// Total returns the total number of samples in a report.
func (rpt *Report) Total() int64 { return rpt.total }
+// OutputFormat returns the output format for the report.
+func (rpt *Report) OutputFormat() int { return rpt.options.OutputFormat }
+
func abs64(i int64) int64 {
if i < 0 {
return -i
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/source.go b/src/cmd/vendor/github.com/google/pprof/internal/report/source.go
index d8b4395265..d2148607ea 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/report/source.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/report/source.go
@@ -122,17 +122,6 @@ func printSource(w io.Writer, rpt *Report) error {
return nil
}
-// printWebSource prints an annotated source listing, include all
-// functions with samples that match the regexp rpt.options.symbol.
-func printWebSource(w io.Writer, rpt *Report, obj plugin.ObjTool) error {
- printHeader(w, rpt)
- if err := PrintWebList(w, rpt, obj, -1); err != nil {
- return err
- }
- printPageClosing(w)
- return nil
-}
-
// sourcePrinter holds state needed for generating source+asm HTML listing.
type sourcePrinter struct {
reader *sourceReader
@@ -198,24 +187,73 @@ type addressRange struct {
score int64 // Used to order ranges for processing
}
-// PrintWebList prints annotated source listing of rpt to w.
+// WebListData holds the data needed to generate HTML source code listing.
+type WebListData struct {
+ Total string
+ Files []WebListFile
+}
+
+// WebListFile holds the per-file information for HTML source code listing.
+type WebListFile struct {
+ Funcs []WebListFunc
+}
+
+// WebListFunc holds the per-function information for HTML source code listing.
+type WebListFunc struct {
+ Name string
+ File string
+ Flat string
+ Cumulative string
+ Percent string
+ Lines []WebListLine
+}
+
+// WebListLine holds the per-source-line information for HTML source code listing.
+type WebListLine struct {
+ SrcLine string
+ HTMLClass string
+ Line int
+ Flat string
+ Cumulative string
+ Instructions []WebListInstruction
+}
+
+// WebListInstruction holds the per-instruction information for HTML source code listing.
+type WebListInstruction struct {
+ NewBlock bool // Insert marker that indicates separation from previous block
+ Flat string
+ Cumulative string
+ Synthetic bool
+ Address uint64
+ Disasm string
+ FileLine string
+ InlinedCalls []WebListCall
+}
+
+// WebListCall holds the per-inlined-call information for HTML source code listing.
+type WebListCall struct {
+ SrcLine string
+ FileBase string
+ Line int
+}
+
+// MakeWebList returns an annotated source listing of rpt.
// rpt.prof should contain inlined call info.
-func PrintWebList(w io.Writer, rpt *Report, obj plugin.ObjTool, maxFiles int) error {
+func MakeWebList(rpt *Report, obj plugin.ObjTool, maxFiles int) (WebListData, error) {
sourcePath := rpt.options.SourcePath
if sourcePath == "" {
wd, err := os.Getwd()
if err != nil {
- return fmt.Errorf("could not stat current dir: %v", err)
+ return WebListData{}, fmt.Errorf("could not stat current dir: %v", err)
}
sourcePath = wd
}
sp := newSourcePrinter(rpt, obj, sourcePath)
if len(sp.interest) == 0 {
- return fmt.Errorf("no matches found for regexp: %s", rpt.options.Symbol)
+ return WebListData{}, fmt.Errorf("no matches found for regexp: %s", rpt.options.Symbol)
}
- sp.print(w, maxFiles, rpt)
- sp.close()
- return nil
+ defer sp.close()
+ return sp.generate(maxFiles, rpt), nil
}
func newSourcePrinter(rpt *Report, obj plugin.ObjTool, sourcePath string) *sourcePrinter {
@@ -566,7 +604,7 @@ func (sp *sourcePrinter) initSamples(flat, cum map[uint64]int64) {
}
}
-func (sp *sourcePrinter) print(w io.Writer, maxFiles int, rpt *Report) {
+func (sp *sourcePrinter) generate(maxFiles int, rpt *Report) WebListData {
// Finalize per-file counts.
for _, file := range sp.files {
seen := map[uint64]bool{}
@@ -598,19 +636,31 @@ func (sp *sourcePrinter) print(w io.Writer, maxFiles int, rpt *Report) {
maxFiles = len(files)
}
sort.Slice(files, order)
+ result := WebListData{
+ Total: rpt.formatValue(rpt.total),
+ }
for i, f := range files {
if i < maxFiles {
- sp.printFile(w, f, rpt)
+ result.Files = append(result.Files, sp.generateFile(f, rpt))
}
}
+ return result
}
-func (sp *sourcePrinter) printFile(w io.Writer, f *sourceFile, rpt *Report) {
+func (sp *sourcePrinter) generateFile(f *sourceFile, rpt *Report) WebListFile {
+ var result WebListFile
for _, fn := range sp.functions(f) {
if fn.cum == 0 {
continue
}
- printFunctionHeader(w, fn.name, f.fname, fn.flat, fn.cum, rpt)
+
+ listfn := WebListFunc{
+ Name: fn.name,
+ File: f.fname,
+ Flat: rpt.formatValue(fn.flat),
+ Cumulative: rpt.formatValue(fn.cum),
+ Percent: measurement.Percentage(fn.cum, rpt.total),
+ }
var asm []assemblyInstruction
for l := fn.begin; l < fn.end; l++ {
lineContents, ok := sp.reader.line(f.fname, l)
@@ -654,10 +704,12 @@ func (sp *sourcePrinter) printFile(w io.Writer, f *sourceFile, rpt *Report) {
})
}
- printFunctionSourceLine(w, l, flatSum, cumSum, lineContents, asm, sp.reader, rpt)
+ listfn.Lines = append(listfn.Lines, makeWebListLine(l, flatSum, cumSum, lineContents, asm, sp.reader, rpt))
}
- printFunctionClosing(w)
+
+ result.Funcs = append(result.Funcs, listfn)
}
+ return result
}
// functions splits apart the lines to show in a file into a list of per-function ranges.
@@ -752,89 +804,58 @@ func (sp *sourcePrinter) objectFile(m *profile.Mapping) plugin.ObjFile {
return object
}
-// printHeader prints the page header for a weblist report.
-func printHeader(w io.Writer, rpt *Report) {
- fmt.Fprintln(w, `
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="UTF-8">
-<title>Pprof listing</title>`)
- fmt.Fprintln(w, weblistPageCSS)
- fmt.Fprintln(w, weblistPageScript)
- fmt.Fprint(w, "</head>\n<body>\n\n")
-
- var labels []string
- for _, l := range ProfileLabels(rpt) {
- labels = append(labels, template.HTMLEscapeString(l))
+// makeWebListLine returns the contents of a single line in a web listing. This includes
+// the source line and the corresponding assembly.
+func makeWebListLine(lineNo int, flat, cum int64, lineContents string,
+ assembly []assemblyInstruction, reader *sourceReader, rpt *Report) WebListLine {
+ line := WebListLine{
+ SrcLine: lineContents,
+ Line: lineNo,
+ Flat: valueOrDot(flat, rpt),
+ Cumulative: valueOrDot(cum, rpt),
}
- fmt.Fprintf(w, `<div class="legend">%s<br>Total: %s</div>`,
- strings.Join(labels, "<br>\n"),
- rpt.formatValue(rpt.total),
- )
-}
-
-// printFunctionHeader prints a function header for a weblist report.
-func printFunctionHeader(w io.Writer, name, path string, flatSum, cumSum int64, rpt *Report) {
- fmt.Fprintf(w, `<h2>%s</h2><p class="filename">%s</p>
-<pre onClick="pprof_toggle_asm(event)">
- Total: %10s %10s (flat, cum) %s
-`,
- template.HTMLEscapeString(name), template.HTMLEscapeString(path),
- rpt.formatValue(flatSum), rpt.formatValue(cumSum),
- measurement.Percentage(cumSum, rpt.total))
-}
-
-// printFunctionSourceLine prints a source line and the corresponding assembly.
-func printFunctionSourceLine(w io.Writer, lineNo int, flat, cum int64, lineContents string,
- assembly []assemblyInstruction, reader *sourceReader, rpt *Report) {
if len(assembly) == 0 {
- fmt.Fprintf(w,
- "<span class=line> %6d</span> <span class=nop> %10s %10s %8s %s </span>\n",
- lineNo,
- valueOrDot(flat, rpt), valueOrDot(cum, rpt),
- "", template.HTMLEscapeString(lineContents))
- return
+ line.HTMLClass = "nop"
+ return line
}
nestedInfo := false
- cl := "deadsrc"
+ line.HTMLClass = "deadsrc"
for _, an := range assembly {
if len(an.inlineCalls) > 0 || an.instruction != synthAsm {
nestedInfo = true
- cl = "livesrc"
+ line.HTMLClass = "livesrc"
}
}
- fmt.Fprintf(w,
- "<span class=line> %6d</span> <span class=%s> %10s %10s %8s %s </span>",
- lineNo, cl,
- valueOrDot(flat, rpt), valueOrDot(cum, rpt),
- "", template.HTMLEscapeString(lineContents))
if nestedInfo {
srcIndent := indentation(lineContents)
- printNested(w, srcIndent, assembly, reader, rpt)
+ line.Instructions = makeWebListInstructions(srcIndent, assembly, reader, rpt)
}
- fmt.Fprintln(w)
+ return line
}
-func printNested(w io.Writer, srcIndent int, assembly []assemblyInstruction, reader *sourceReader, rpt *Report) {
- fmt.Fprint(w, "<span class=asm>")
+func makeWebListInstructions(srcIndent int, assembly []assemblyInstruction, reader *sourceReader, rpt *Report) []WebListInstruction {
+ var result []WebListInstruction
var curCalls []callID
for i, an := range assembly {
- if an.startsBlock && i != 0 {
- // Insert a separator between discontiguous blocks.
- fmt.Fprintf(w, " %8s %28s\n", "", "⋮")
- }
-
var fileline string
if an.file != "" {
fileline = fmt.Sprintf("%s:%d", template.HTMLEscapeString(filepath.Base(an.file)), an.line)
}
- flat, cum := an.flat, an.cum
+ text := strings.Repeat(" ", srcIndent+4+4*len(an.inlineCalls)) + an.instruction
+ inst := WebListInstruction{
+ NewBlock: (an.startsBlock && i != 0),
+ Flat: valueOrDot(an.flat, rpt),
+ Cumulative: valueOrDot(an.cum, rpt),
+ Synthetic: (an.instruction == synthAsm),
+ Address: an.address,
+ Disasm: rightPad(text, 80),
+ FileLine: fileline,
+ }
- // Print inlined call context.
+ // Add inlined call context.
for j, c := range an.inlineCalls {
if j < len(curCalls) && curCalls[j] == c {
// Skip if same as previous instruction.
@@ -845,36 +866,18 @@ func printNested(w io.Writer, srcIndent int, assembly []assemblyInstruction, rea
if !ok {
fline = ""
}
- text := strings.Repeat(" ", srcIndent+4+4*j) + strings.TrimSpace(fline)
- fmt.Fprintf(w, " %8s %10s %10s %8s <span class=inlinesrc>%s</span> <span class=unimportant>%s:%d</span>\n",
- "", "", "", "",
- template.HTMLEscapeString(rightPad(text, 80)),
- template.HTMLEscapeString(filepath.Base(c.file)), c.line)
+ srcCode := strings.Repeat(" ", srcIndent+4+4*j) + strings.TrimSpace(fline)
+ inst.InlinedCalls = append(inst.InlinedCalls, WebListCall{
+ SrcLine: rightPad(srcCode, 80),
+ FileBase: filepath.Base(c.file),
+ Line: c.line,
+ })
}
curCalls = an.inlineCalls
- if an.instruction == synthAsm {
- continue
- }
- text := strings.Repeat(" ", srcIndent+4+4*len(curCalls)) + an.instruction
- fmt.Fprintf(w, " %8s %10s %10s %8x: %s <span class=unimportant>%s</span>\n",
- "", valueOrDot(flat, rpt), valueOrDot(cum, rpt), an.address,
- template.HTMLEscapeString(rightPad(text, 80)),
- // fileline should not be escaped since it was formed by appending
- // line number (just digits) to an escaped file name. Escaping here
- // would cause double-escaping of file name.
- fileline)
- }
- fmt.Fprint(w, "</span>")
-}
-
-// printFunctionClosing prints the end of a function in a weblist report.
-func printFunctionClosing(w io.Writer) {
- fmt.Fprintln(w, "</pre>")
-}
-// printPageClosing prints the end of the page in a weblist report.
-func printPageClosing(w io.Writer) {
- fmt.Fprintln(w, weblistPageClosing)
+ result = append(result, inst)
+ }
+ return result
}
// getSourceFromFile collects the sources of a function from a source
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go b/src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go
index 851693f1d0..614a5ee293 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/report/source_html.go
@@ -69,7 +69,3 @@ function pprof_toggle_asm(e) {
}
}
</script>`
-
-const weblistPageClosing = `
-</body>
-</html>`
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/symbolizer/symbolizer.go b/src/cmd/vendor/github.com/google/pprof/internal/symbolizer/symbolizer.go
index 5ca71ab8be..70b4047269 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/symbolizer/symbolizer.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/symbolizer/symbolizer.go
@@ -133,22 +133,80 @@ func doLocalSymbolize(prof *profile.Profile, fast, force bool, obj plugin.ObjToo
}
}
- mt, err := newMapping(prof, obj, ui, force)
- if err != nil {
- return err
+ functions := map[profile.Function]*profile.Function{}
+ addFunction := func(f *profile.Function) *profile.Function {
+ if fp := functions[*f]; fp != nil {
+ return fp
+ }
+ functions[*f] = f
+ f.ID = uint64(len(prof.Function)) + 1
+ prof.Function = append(prof.Function, f)
+ return f
+ }
+
+ missingBinaries := false
+ mappingLocs := map[*profile.Mapping][]*profile.Location{}
+ for _, l := range prof.Location {
+ mappingLocs[l.Mapping] = append(mappingLocs[l.Mapping], l)
}
- defer mt.close()
+ for midx, m := range prof.Mapping {
+ locs := mappingLocs[m]
+ if len(locs) == 0 {
+ // The mapping is dangling and has no locations pointing to it.
+ continue
+ }
+ // Do not attempt to re-symbolize a mapping that has already been symbolized.
+ if !force && (m.HasFunctions || m.HasFilenames || m.HasLineNumbers) {
+ continue
+ }
+ if m.File == "" {
+ if midx == 0 {
+ ui.PrintErr("Main binary filename not available.")
+ continue
+ }
+ missingBinaries = true
+ continue
+ }
+ if m.Unsymbolizable() {
+ // Skip well-known system mappings
+ continue
+ }
+ if m.BuildID == "" {
+ if u, err := url.Parse(m.File); err == nil && u.IsAbs() && strings.Contains(strings.ToLower(u.Scheme), "http") {
+ // Skip mappings pointing to a source URL
+ continue
+ }
+ }
- functions := make(map[profile.Function]*profile.Function)
- for _, l := range mt.prof.Location {
- m := l.Mapping
- segment := mt.segments[m]
- if segment == nil {
- // Nothing to do.
+ name := filepath.Base(m.File)
+ if m.BuildID != "" {
+ name += fmt.Sprintf(" (build ID %s)", m.BuildID)
+ }
+ f, err := obj.Open(m.File, m.Start, m.Limit, m.Offset, m.KernelRelocationSymbol)
+ if err != nil {
+ ui.PrintErr("Local symbolization failed for ", name, ": ", err)
+ missingBinaries = true
continue
}
+ if fid := f.BuildID(); m.BuildID != "" && fid != "" && fid != m.BuildID {
+ ui.PrintErr("Local symbolization failed for ", name, ": build ID mismatch")
+ f.Close()
+ continue
+ }
+ symbolizeOneMapping(m, locs, f, addFunction)
+ f.Close()
+ }
- stack, err := segment.SourceLine(l.Address)
+ if missingBinaries {
+ ui.PrintErr("Some binary filenames not available. Symbolization may be incomplete.\n" +
+ "Try setting PPROF_BINARY_PATH to the search path for local binaries.")
+ }
+ return nil
+}
+
+func symbolizeOneMapping(m *profile.Mapping, locs []*profile.Location, obj plugin.ObjFile, addFunction func(*profile.Function) *profile.Function) {
+ for _, l := range locs {
+ stack, err := obj.SourceLine(l.Address)
if err != nil || len(stack) == 0 {
// No answers from addr2line.
continue
@@ -166,18 +224,11 @@ func doLocalSymbolize(prof *profile.Profile, fast, force bool, obj plugin.ObjToo
if frame.Line != 0 {
m.HasLineNumbers = true
}
- f := &profile.Function{
+ f := addFunction(&profile.Function{
Name: frame.Func,
SystemName: frame.Func,
Filename: frame.File,
- }
- if fp := functions[*f]; fp != nil {
- f = fp
- } else {
- functions[*f] = f
- f.ID = uint64(len(mt.prof.Function)) + 1
- mt.prof.Function = append(mt.prof.Function, f)
- }
+ })
l.Line[i] = profile.Line{
Function: f,
Line: int64(frame.Line),
@@ -189,8 +240,6 @@ func doLocalSymbolize(prof *profile.Profile, fast, force bool, obj plugin.ObjToo
m.HasInlineFrames = true
}
}
-
- return nil
}
// Demangle updates the function names in a profile with demangled C++
@@ -294,87 +343,3 @@ func removeMatching(name string, start, end byte) string {
}
return name
}
-
-// newMapping creates a mappingTable for a profile.
-func newMapping(prof *profile.Profile, obj plugin.ObjTool, ui plugin.UI, force bool) (*mappingTable, error) {
- mt := &mappingTable{
- prof: prof,
- segments: make(map[*profile.Mapping]plugin.ObjFile),
- }
-
- // Identify used mappings
- mappings := make(map[*profile.Mapping]bool)
- for _, l := range prof.Location {
- mappings[l.Mapping] = true
- }
-
- missingBinaries := false
- for midx, m := range prof.Mapping {
- if !mappings[m] {
- continue
- }
-
- // Do not attempt to re-symbolize a mapping that has already been symbolized.
- if !force && (m.HasFunctions || m.HasFilenames || m.HasLineNumbers) {
- continue
- }
-
- if m.File == "" {
- if midx == 0 {
- ui.PrintErr("Main binary filename not available.")
- continue
- }
- missingBinaries = true
- continue
- }
-
- // Skip well-known system mappings
- if m.Unsymbolizable() {
- continue
- }
-
- // Skip mappings pointing to a source URL
- if m.BuildID == "" {
- if u, err := url.Parse(m.File); err == nil && u.IsAbs() && strings.Contains(strings.ToLower(u.Scheme), "http") {
- continue
- }
- }
-
- name := filepath.Base(m.File)
- if m.BuildID != "" {
- name += fmt.Sprintf(" (build ID %s)", m.BuildID)
- }
- f, err := obj.Open(m.File, m.Start, m.Limit, m.Offset, m.KernelRelocationSymbol)
- if err != nil {
- ui.PrintErr("Local symbolization failed for ", name, ": ", err)
- missingBinaries = true
- continue
- }
- if fid := f.BuildID(); m.BuildID != "" && fid != "" && fid != m.BuildID {
- ui.PrintErr("Local symbolization failed for ", name, ": build ID mismatch")
- f.Close()
- continue
- }
-
- mt.segments[m] = f
- }
- if missingBinaries {
- ui.PrintErr("Some binary filenames not available. Symbolization may be incomplete.\n" +
- "Try setting PPROF_BINARY_PATH to the search path for local binaries.")
- }
- return mt, nil
-}
-
-// mappingTable contains the mechanisms for symbolization of a
-// profile.
-type mappingTable struct {
- prof *profile.Profile
- segments map[*profile.Mapping]plugin.ObjFile
-}
-
-// close releases any external processes being used for the mapping.
-func (mt *mappingTable) close() {
- for _, segment := range mt.segments {
- segment.Close()
- }
-}
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/profile.go b/src/cmd/vendor/github.com/google/pprof/profile/profile.go
index 62df80a556..5551eb0bfa 100644
--- a/src/cmd/vendor/github.com/google/pprof/profile/profile.go
+++ b/src/cmd/vendor/github.com/google/pprof/profile/profile.go
@@ -847,7 +847,7 @@ func (p *Profile) HasFileLines() bool {
// "[vdso]", [vsyscall]" and some others, see the code.
func (m *Mapping) Unsymbolizable() bool {
name := filepath.Base(m.File)
- return strings.HasPrefix(name, "[") || strings.HasPrefix(name, "linux-vdso") || strings.HasPrefix(m.File, "/dev/dri/")
+ return strings.HasPrefix(name, "[") || strings.HasPrefix(name, "linux-vdso") || strings.HasPrefix(m.File, "/dev/dri/") || m.File == "//anon"
}
// Copy makes a fully independent copy of a profile.