aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/vendor/github.com/google/pprof/internal/driver
diff options
context:
space:
mode:
authorDaniel Martí <mvdan@mvdan.cc>2018-04-06 22:38:48 +0100
committerBrad Fitzpatrick <bradfitz@golang.org>2018-04-06 23:03:41 +0000
commit31db81d329ddeacc4ba18671783cca5f1ddb4b9d (patch)
treeb767e593fda986a2cd5bdeb6e88cb438a19e69ed /src/cmd/vendor/github.com/google/pprof/internal/driver
parent4acb305d8bf421ccd8963faa140ce57094ce36ae (diff)
downloadgo-31db81d329ddeacc4ba18671783cca5f1ddb4b9d.tar.xz
cmd/vendor/.../pprof: update to 0f7d9ba1
In particular, to pull a few fixes that were causing some tests to be flaky on our build dashboard. Fixes #24405. Fixes #24508. Fixes #24611. Change-Id: I713156ad11c924e4a4b603144d10395523d526ed Reviewed-on: https://go-review.googlesource.com/105275 Run-TryBot: Daniel Martí <mvdan@mvdan.cc> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Diffstat (limited to 'src/cmd/vendor/github.com/google/pprof/internal/driver')
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/driver.go4
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/driver_test.go186
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go4
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go39
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/flamegraph.go2
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/interactive.go9
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/options.go4
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go36
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/webui.go28
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/webui_test.go5
10 files changed, 156 insertions, 161 deletions
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 c2b1cd082b..3b7439fc9a 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
@@ -54,7 +54,7 @@ func PProf(eo *plugin.Options) error {
}
if src.HTTPHostport != "" {
- return serveWebInterface(src.HTTPHostport, p, o, true)
+ return serveWebInterface(src.HTTPHostport, p, o)
}
return interactive(p, o)
}
@@ -138,7 +138,7 @@ func generateReport(p *profile.Profile, cmd []string, vars variables, o *plugin.
// Output to specified file.
o.UI.PrintErr("Generating report in ", output)
- out, err := os.Create(output)
+ out, err := o.Writer.Open(output)
if err != nil {
return err
}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_test.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_test.go
index 0604da911c..06219eae64 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_test.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/driver_test.go
@@ -96,114 +96,118 @@ func TestParse(t *testing.T) {
baseVars := pprofVariables
defer func() { pprofVariables = baseVars }()
for _, tc := range testcase {
- // Reset the pprof variables before processing
- pprofVariables = baseVars.makeCopy()
+ t.Run(tc.flags+":"+tc.source, func(t *testing.T) {
+ // Reset the pprof variables before processing
+ pprofVariables = baseVars.makeCopy()
- f := baseFlags()
- f.args = []string{tc.source}
+ testUI := &proftest.TestUI{T: t, AllowRx: "Generating report in|Ignoring local file|expression matched no samples|Interpreted .* as range, not regexp"}
- flags := strings.Split(tc.flags, ",")
+ f := baseFlags()
+ f.args = []string{tc.source}
- // Skip the output format in the first flag, to output to a proto
- addFlags(&f, flags[1:])
+ flags := strings.Split(tc.flags, ",")
- // Encode profile into a protobuf and decode it again.
- protoTempFile, err := ioutil.TempFile("", "profile_proto")
- if err != nil {
- t.Errorf("cannot create tempfile: %v", err)
- }
- defer os.Remove(protoTempFile.Name())
- defer protoTempFile.Close()
- f.strings["output"] = protoTempFile.Name()
-
- if flags[0] == "topproto" {
- f.bools["proto"] = false
- f.bools["topproto"] = true
- }
+ // Skip the output format in the first flag, to output to a proto
+ addFlags(&f, flags[1:])
- // First pprof invocation to save the profile into a profile.proto.
- o1 := setDefaults(nil)
- o1.Flagset = f
- o1.Fetch = testFetcher{}
- o1.Sym = testSymbolizer{}
- if err := PProf(o1); err != nil {
- t.Errorf("%s %q: %v", tc.source, tc.flags, err)
- continue
- }
- // Reset the pprof variables after the proto invocation
- pprofVariables = baseVars.makeCopy()
+ // Encode profile into a protobuf and decode it again.
+ protoTempFile, err := ioutil.TempFile("", "profile_proto")
+ if err != nil {
+ t.Errorf("cannot create tempfile: %v", err)
+ }
+ defer os.Remove(protoTempFile.Name())
+ defer protoTempFile.Close()
+ f.strings["output"] = protoTempFile.Name()
- // Read the profile from the encoded protobuf
- outputTempFile, err := ioutil.TempFile("", "profile_output")
- if err != nil {
- t.Errorf("cannot create tempfile: %v", err)
- }
- defer os.Remove(outputTempFile.Name())
- defer outputTempFile.Close()
- f.strings["output"] = outputTempFile.Name()
- f.args = []string{protoTempFile.Name()}
+ if flags[0] == "topproto" {
+ f.bools["proto"] = false
+ f.bools["topproto"] = true
+ }
- var solution string
- // Apply the flags for the second pprof run, and identify name of
- // the file containing expected results
- if flags[0] == "topproto" {
- solution = solutionFilename(tc.source, &f)
- delete(f.bools, "topproto")
- f.bools["text"] = true
- } else {
- delete(f.bools, "proto")
- addFlags(&f, flags[:1])
- solution = solutionFilename(tc.source, &f)
- }
- // The add_comment flag is not idempotent so only apply it on the first run.
- delete(f.strings, "add_comment")
+ // First pprof invocation to save the profile into a profile.proto.
+ o1 := setDefaults(nil)
+ o1.Flagset = f
+ o1.Fetch = testFetcher{}
+ o1.Sym = testSymbolizer{}
+ o1.UI = testUI
+ if err := PProf(o1); err != nil {
+ t.Fatalf("%s %q: %v", tc.source, tc.flags, err)
+ }
+ // Reset the pprof variables after the proto invocation
+ pprofVariables = baseVars.makeCopy()
- // Second pprof invocation to read the profile from profile.proto
- // and generate a report.
- o2 := setDefaults(nil)
- o2.Flagset = f
- o2.Sym = testSymbolizeDemangler{}
- o2.Obj = new(mockObjTool)
+ // Read the profile from the encoded protobuf
+ outputTempFile, err := ioutil.TempFile("", "profile_output")
+ if err != nil {
+ t.Errorf("cannot create tempfile: %v", err)
+ }
+ defer os.Remove(outputTempFile.Name())
+ defer outputTempFile.Close()
+ f.strings["output"] = outputTempFile.Name()
+ f.args = []string{protoTempFile.Name()}
- if err := PProf(o2); err != nil {
- t.Errorf("%s: %v", tc.source, err)
- }
- b, err := ioutil.ReadFile(outputTempFile.Name())
- if err != nil {
- t.Errorf("Failed to read profile %s: %v", outputTempFile.Name(), err)
- }
+ var solution string
+ // Apply the flags for the second pprof run, and identify name of
+ // the file containing expected results
+ if flags[0] == "topproto" {
+ solution = solutionFilename(tc.source, &f)
+ delete(f.bools, "topproto")
+ f.bools["text"] = true
+ } else {
+ delete(f.bools, "proto")
+ addFlags(&f, flags[:1])
+ solution = solutionFilename(tc.source, &f)
+ }
+ // The add_comment flag is not idempotent so only apply it on the first run.
+ delete(f.strings, "add_comment")
- // Read data file with expected solution
- solution = "testdata/" + solution
- sbuf, err := ioutil.ReadFile(solution)
- if err != nil {
- t.Errorf("reading solution file %s: %v", solution, err)
- continue
- }
- if runtime.GOOS == "windows" {
- sbuf = bytes.Replace(sbuf, []byte("testdata/"), []byte("testdata\\"), -1)
- sbuf = bytes.Replace(sbuf, []byte("/path/to/"), []byte("\\path\\to\\"), -1)
- }
+ // Second pprof invocation to read the profile from profile.proto
+ // and generate a report.
+ o2 := setDefaults(nil)
+ o2.Flagset = f
+ o2.Sym = testSymbolizeDemangler{}
+ o2.Obj = new(mockObjTool)
+ o2.UI = testUI
- if flags[0] == "svg" {
- b = removeScripts(b)
- sbuf = removeScripts(sbuf)
- }
+ if err := PProf(o2); err != nil {
+ t.Errorf("%s: %v", tc.source, err)
+ }
+ b, err := ioutil.ReadFile(outputTempFile.Name())
+ if err != nil {
+ t.Errorf("Failed to read profile %s: %v", outputTempFile.Name(), err)
+ }
- if string(b) != string(sbuf) {
- t.Errorf("diff %s %s", solution, tc.source)
- d, err := proftest.Diff(sbuf, b)
+ // Read data file with expected solution
+ solution = "testdata/" + solution
+ sbuf, err := ioutil.ReadFile(solution)
if err != nil {
- t.Fatalf("diff %s %v", solution, err)
+ t.Fatalf("reading solution file %s: %v", solution, err)
}
- t.Errorf("%s\n%s\n", solution, d)
- if *updateFlag {
- err := ioutil.WriteFile(solution, b, 0644)
+ if runtime.GOOS == "windows" {
+ sbuf = bytes.Replace(sbuf, []byte("testdata/"), []byte("testdata\\"), -1)
+ sbuf = bytes.Replace(sbuf, []byte("/path/to/"), []byte("\\path\\to\\"), -1)
+ }
+
+ if flags[0] == "svg" {
+ b = removeScripts(b)
+ sbuf = removeScripts(sbuf)
+ }
+
+ if string(b) != string(sbuf) {
+ t.Errorf("diff %s %s", solution, tc.source)
+ d, err := proftest.Diff(sbuf, b)
if err != nil {
- t.Errorf("failed to update the solution file %q: %v", solution, err)
+ t.Fatalf("diff %s %v", solution, err)
+ }
+ t.Errorf("%s\n%s\n", solution, d)
+ if *updateFlag {
+ err := ioutil.WriteFile(solution, b, 0644)
+ if err != nil {
+ t.Errorf("failed to update the solution file %q: %v", solution, err)
+ }
}
}
- }
+ })
}
}
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 a929b0f790..1b34e70bea 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
@@ -407,6 +407,7 @@ mapping:
if matches, err := filepath.Glob(filepath.Join(path, m.BuildID, "*")); err == nil {
fileNames = append(fileNames, matches...)
}
+ fileNames = append(fileNames, filepath.Join(path, m.File, m.BuildID)) // perf path format
}
if m.File != "" {
// Try both the basename and the full path, to support the same directory
@@ -534,7 +535,8 @@ func convertPerfData(perfPath string, ui plugin.UI) (*os.File, error) {
return nil, err
}
deferDeleteTempFile(profile.Name())
- cmd := exec.Command("perf_to_profile", perfPath, profile.Name())
+ cmd := exec.Command("perf_to_profile", "-i", perfPath, "-o", profile.Name(), "-f")
+ cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
if err := cmd.Run(); err != nil {
profile.Close()
return nil, fmt.Errorf("failed to convert perf.data file. Try github.com/google/perf_data_converter: %v", err)
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go
index c80a0dbc1d..f15328bfae 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch_test.go
@@ -283,8 +283,10 @@ func TestFetchWithBase(t *testing.T) {
}
f.args = tc.sources
- o := setDefaults(nil)
- o.Flagset = f
+ o := setDefaults(&plugin.Options{
+ UI: &proftest.TestUI{T: t, AllowRx: "Local symbolization failed|Some binary filenames not available"},
+ Flagset: f,
+ })
src, _, err := parseFlags(o)
if err != nil {
@@ -397,18 +399,6 @@ func TestHttpsInsecure(t *testing.T) {
}()
defer l.Close()
- go func() {
- deadline := time.Now().Add(5 * time.Second)
- for time.Now().Before(deadline) {
- // Simulate a hotspot function. Spin in the inner loop for 100M iterations
- // to ensure we get most of the samples landed here rather than in the
- // library calls. We assume Go compiler won't elide the empty loop.
- for i := 0; i < 1e8; i++ {
- }
- runtime.Gosched()
- }
- }()
-
outputTempFile, err := ioutil.TempFile("", "profile_output")
if err != nil {
t.Fatalf("Failed to create tempfile: %v", err)
@@ -416,7 +406,7 @@ func TestHttpsInsecure(t *testing.T) {
defer os.Remove(outputTempFile.Name())
defer outputTempFile.Close()
- address := "https+insecure://" + l.Addr().String() + "/debug/pprof/profile"
+ address := "https+insecure://" + l.Addr().String() + "/debug/pprof/goroutine"
s := &source{
Sources: []string{address},
Seconds: 10,
@@ -435,31 +425,14 @@ func TestHttpsInsecure(t *testing.T) {
if len(p.SampleType) == 0 {
t.Fatalf("fetchProfiles(%s) got empty profile: len(p.SampleType)==0", address)
}
- switch runtime.GOOS {
- case "plan9":
- // CPU profiling is not supported on Plan9; see golang.org/issues/22564.
- return
- case "darwin":
- if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
- // CPU profiling on iOS os not symbolized; see golang.org/issues/22612.
- return
- }
- }
if len(p.Function) == 0 {
t.Fatalf("fetchProfiles(%s) got non-symbolized profile: len(p.Function)==0", address)
}
- if err := checkProfileHasFunction(p, "TestHttpsInsecure"); !badSigprofOS[runtime.GOOS] && err != nil {
+ if err := checkProfileHasFunction(p, "TestHttpsInsecure"); err != nil {
t.Fatalf("fetchProfiles(%s) %v", address, err)
}
}
-// Some operating systems don't trigger the profiling signal right.
-// See https://github.com/golang/go/issues/13841.
-var badSigprofOS = map[string]bool{
- "darwin": true,
- "netbsd": true,
-}
-
func checkProfileHasFunction(p *profile.Profile, fname string) error {
for _, f := range p.Function {
if strings.Contains(f.Name, fname) {
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/flamegraph.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/flamegraph.go
index 10588d6262..29a41011bb 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/flamegraph.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/flamegraph.go
@@ -92,7 +92,7 @@ func (ui *webInterface) flamegraph(w http.ResponseWriter, req *http.Request) {
return
}
- ui.render(w, "/flamegraph", "flamegraph", rpt, errList, config.Labels, webArgs{
+ ui.render(w, "flamegraph", rpt, errList, config.Labels, webArgs{
FlameGraph: template.JS(b),
Nodes: nodeArr,
})
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive.go
index b893697b62..bebfbbec1e 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/interactive.go
@@ -149,9 +149,14 @@ func greetings(p *profile.Profile, ui plugin.UI) {
numLabelUnits := identifyNumLabelUnits(p, ui)
ropt, err := reportOptions(p, numLabelUnits, pprofVariables)
if err == nil {
- ui.Print(strings.Join(report.ProfileLabels(report.New(p, ropt)), "\n"))
+ rpt := report.New(p, ropt)
+ ui.Print(strings.Join(report.ProfileLabels(rpt), "\n"))
+ if rpt.Total() == 0 && len(p.SampleType) > 1 {
+ ui.Print(`No samples were found with the default sample value type.`)
+ ui.Print(`Try "sample_index" command to analyze different sample values.`, "\n")
+ }
}
- ui.Print("Entering interactive mode (type \"help\" for commands, \"o\" for options)")
+ ui.Print(`Entering interactive mode (type "help" for commands, "o" for options)`)
}
// shortcuts represents composite commands that expand into a sequence
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/options.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/options.go
index cb20e948b4..34167d4bf5 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/options.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/options.go
@@ -128,6 +128,10 @@ func (ui *stdUI) IsTerminal() bool {
return false
}
+func (ui *stdUI) WantBrowser() bool {
+ return true
+}
+
func (ui *stdUI) SetAutoComplete(func(string) string) {
}
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 5d2821cd42..e9bc872035 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
@@ -233,7 +233,7 @@ table tr td {
{{define "header"}}
<div class="header">
<div class="title">
- <h1><a href="/">pprof</a></h1>
+ <h1><a href="./">pprof</a></h1>
</div>
<div id="view" class="menu-item">
@@ -242,12 +242,12 @@ table tr td {
<i class="downArrow"></i>
</div>
<div class="submenu">
- <a title="{{.Help.top}}" href="/top" id="topbtn">Top</a>
- <a title="{{.Help.graph}}" href="/" id="graphbtn">Graph</a>
- <a title="{{.Help.flamegraph}}" href="/flamegraph" id="flamegraph">Flame Graph</a>
- <a title="{{.Help.peek}}" href="/peek" id="peek">Peek</a>
- <a title="{{.Help.list}}" href="/source" id="list">Source</a>
- <a title="{{.Help.disasm}}" href="/disasm" id="disasm">Disassemble</a>
+ <a title="{{.Help.top}}" href="./top" id="topbtn">Top</a>
+ <a title="{{.Help.graph}}" href="./" id="graphbtn">Graph</a>
+ <a title="{{.Help.flamegraph}}" href="./flamegraph" id="flamegraph">Flame Graph</a>
+ <a title="{{.Help.peek}}" href="./peek" id="peek">Peek</a>
+ <a title="{{.Help.list}}" href="./source" id="list">Source</a>
+ <a title="{{.Help.disasm}}" href="./disasm" id="disasm">Disassemble</a>
</div>
</div>
@@ -257,12 +257,12 @@ table tr td {
<i class="downArrow"></i>
</div>
<div class="submenu">
- <a title="{{.Help.focus}}" href="{{.BaseURL}}" id="focus">Focus</a>
- <a title="{{.Help.ignore}}" href="{{.BaseURL}}" id="ignore">Ignore</a>
- <a title="{{.Help.hide}}" href="{{.BaseURL}}" id="hide">Hide</a>
- <a title="{{.Help.show}}" href="{{.BaseURL}}" id="show">Show</a>
+ <a title="{{.Help.focus}}" href="?" id="focus">Focus</a>
+ <a title="{{.Help.ignore}}" href="?" id="ignore">Ignore</a>
+ <a title="{{.Help.hide}}" href="?" id="hide">Hide</a>
+ <a title="{{.Help.show}}" href="?" id="show">Show</a>
<hr>
- <a title="{{.Help.reset}}" href="{{.BaseURL}}">Reset</a>
+ <a title="{{.Help.reset}}" href="?">Reset</a>
</div>
</div>
@@ -295,7 +295,7 @@ table tr td {
{{.HTMLBody}}
</div>
{{template "script" .}}
- <script>viewer({{.BaseURL}}, {{.Nodes}});</script>
+ <script>viewer(new URL(window.location.href), {{.Nodes}});</script>
</body>
</html>
{{end}}
@@ -597,7 +597,7 @@ function viewer(baseUrl, nodes) {
function handleKey(e) {
if (e.keyCode != 13) return;
window.location.href =
- updateUrl(new URL({{.BaseURL}}, window.location.href), 'f');
+ updateUrl(new URL(window.location.href), 'f');
e.preventDefault();
}
@@ -963,7 +963,7 @@ function viewer(baseUrl, nodes) {
bindSort('namehdr', 'Name');
}
- viewer({{.BaseURL}}, {{.Nodes}});
+ viewer(new URL(window.location.href), {{.Nodes}});
makeTopTable({{.Total}}, {{.Top}});
</script>
</body>
@@ -986,7 +986,7 @@ function viewer(baseUrl, nodes) {
{{.HTMLBody}}
</div>
{{template "script" .}}
- <script>viewer({{.BaseURL}}, null);</script>
+ <script>viewer(new URL(window.location.href), null);</script>
</body>
</html>
{{end}}
@@ -1007,7 +1007,7 @@ function viewer(baseUrl, nodes) {
</pre>
</div>
{{template "script" .}}
- <script>viewer({{.BaseURL}}, null);</script>
+ <script>viewer(new URL(window.location.href), null);</script>
</body>
</html>
{{end}}
@@ -1044,7 +1044,7 @@ function viewer(baseUrl, nodes) {
<div id="flamegraphdetails" class="flamegraph-details"></div>
</div>
{{template "script" .}}
- <script>viewer({{.BaseURL}}, {{.Nodes}});</script>
+ <script>viewer(new URL(window.location.href), {{.Nodes}});</script>
<script>{{template "d3script" .}}</script>
<script>{{template "d3tipscript" .}}</script>
<script>{{template "d3flamegraphscript" .}}</script>
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 20d4e025f4..89bc558668 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
@@ -69,7 +69,6 @@ func (ec *errorCatcher) PrintErr(args ...interface{}) {
// webArgs contains arguments passed to templates in webhtml.go.
type webArgs struct {
- BaseURL string
Title string
Errors []string
Total int64
@@ -82,7 +81,7 @@ type webArgs struct {
FlameGraph template.JS
}
-func serveWebInterface(hostport string, p *profile.Profile, o *plugin.Options, wantBrowser bool) error {
+func serveWebInterface(hostport string, p *profile.Profile, o *plugin.Options) error {
host, port, err := getHostAndPort(hostport)
if err != nil {
return err
@@ -117,7 +116,7 @@ func serveWebInterface(hostport string, p *profile.Profile, o *plugin.Options, w
},
}
- if wantBrowser {
+ if o.UI.WantBrowser() {
go openBrowser("http://"+args.Hostport, o)
}
return server(args)
@@ -172,7 +171,15 @@ func defaultWebServer(args *plugin.HTTPServerArgs) error {
}
h.ServeHTTP(w, req)
})
- s := &http.Server{Handler: handler}
+
+ // We serve the ui at /ui/ and redirect there from the root. This is done
+ // to surface any problems with serving the ui at a non-root early. See:
+ //
+ // https://github.com/google/pprof/pull/348
+ mux := http.NewServeMux()
+ mux.Handle("/ui/", http.StripPrefix("/ui", handler))
+ mux.Handle("/", http.RedirectHandler("/ui/", http.StatusTemporaryRedirect))
+ s := &http.Server{Handler: mux}
return s.Serve(ln)
}
@@ -248,11 +255,10 @@ func (ui *webInterface) makeReport(w http.ResponseWriter, req *http.Request,
}
// render generates html using the named template based on the contents of data.
-func (ui *webInterface) render(w http.ResponseWriter, baseURL, tmpl string,
+func (ui *webInterface) render(w http.ResponseWriter, tmpl string,
rpt *report.Report, errList, legend []string, data webArgs) {
file := getFromLegend(legend, "File: ", "unknown")
profile := getFromLegend(legend, "Type: ", "unknown")
- data.BaseURL = baseURL
data.Title = file + " " + profile
data.Errors = errList
data.Total = rpt.Total()
@@ -297,7 +303,7 @@ func (ui *webInterface) dot(w http.ResponseWriter, req *http.Request) {
nodes = append(nodes, n.Info.Name)
}
- ui.render(w, "/", "graph", rpt, errList, legend, webArgs{
+ ui.render(w, "graph", rpt, errList, legend, webArgs{
HTMLBody: template.HTML(string(svg)),
Nodes: nodes,
})
@@ -332,7 +338,7 @@ func (ui *webInterface) top(w http.ResponseWriter, req *http.Request) {
nodes = append(nodes, item.Name)
}
- ui.render(w, "/top", "top", rpt, errList, legend, webArgs{
+ ui.render(w, "top", rpt, errList, legend, webArgs{
Top: top,
Nodes: nodes,
})
@@ -354,7 +360,7 @@ func (ui *webInterface) disasm(w http.ResponseWriter, req *http.Request) {
}
legend := report.ProfileLabels(rpt)
- ui.render(w, "/disasm", "plaintext", rpt, errList, legend, webArgs{
+ ui.render(w, "plaintext", rpt, errList, legend, webArgs{
TextBody: out.String(),
})
@@ -378,7 +384,7 @@ func (ui *webInterface) source(w http.ResponseWriter, req *http.Request) {
}
legend := report.ProfileLabels(rpt)
- ui.render(w, "/source", "sourcelisting", rpt, errList, legend, webArgs{
+ ui.render(w, "sourcelisting", rpt, errList, legend, webArgs{
HTMLBody: template.HTML(body.String()),
})
}
@@ -399,7 +405,7 @@ func (ui *webInterface) peek(w http.ResponseWriter, req *http.Request) {
}
legend := report.ProfileLabels(rpt)
- ui.render(w, "/peek", "plaintext", rpt, errList, legend, webArgs{
+ ui.render(w, "plaintext", rpt, errList, legend, webArgs{
TextBody: out.String(),
})
}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/webui_test.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/webui_test.go
index 424752fd1f..7e061699ce 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/driver/webui_test.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/webui_test.go
@@ -28,6 +28,7 @@ import (
"testing"
"github.com/google/pprof/internal/plugin"
+ "github.com/google/pprof/internal/proftest"
"github.com/google/pprof/profile"
)
@@ -55,9 +56,9 @@ func TestWebInterface(t *testing.T) {
// Start server and wait for it to be initialized
go serveWebInterface("unused:1234", prof, &plugin.Options{
Obj: fakeObjTool{},
- UI: &stdUI{},
+ UI: &proftest.TestUI{},
HTTPServer: creator,
- }, false)
+ })
<-serverCreated
defer server.Close()