Permalink
Browse files

Added an interactive web interface (#154)

* Added an interactive web interface triggered by passing -http=port
on the command line.  The interface is available by visiting
localhost:port in a browser.

Requirements:
* Graphviz must be installed.
* Browser must support Javascript.
* Tested in recent stable versions of chrome and firefox.

Features:
* The entry point is a dot graph display (equivalent to "web" output).
* Nodes in the graph can be selected by clicking.
* A regular expression can also be typed in for selection.
* The current selection (either list of nodes or a regexp)
  can be focused, ignored, or hidden.
* Source code or disassembly of the current selection can be displayed.

* Remove unused function.

* Skip graph generation test if graphviz is not installed.

* Added -http port and the various modes of using pprof to the
usage message.

* Web interface now supports "show" option.

* Web interface automatically opens the browser pointed at
the page corresponding to command line arguments.

* Some tweaks for firefox.

* Handle review comments (better usage message, more testing).

* Handled review comments:

1. Capture and display errors like "Focus expression matched no samples".
2. Re-ordered buttons to match other interfaces.
3. Use UI.PrintErr to print error messages.

* Handle javascript code review comments (a bunch of cleanups).
Also added pprof binary to .gitignore.
  • Loading branch information...
ghemawat authored and aalexand committed Jul 14, 2017
1 parent 5bd319a commit f83a3d89c18c445178f794d525bf3013ef7b3330
@@ -5,3 +5,4 @@
.*.swp
core
coverage.txt
pprof
@@ -77,6 +77,19 @@ This will open a simple shell that takes pprof commands to generate reports.
Type 'help' for available commands/options.
```
## Run pprof via a web interface
If the `-http=port` option is specified, pprof starts a web server at
the specified port that provides an interactive web-based interface to pprof.
```
pprof -http=[port] [main_binary] profile.pb.gz
```
The preceding command should automatically open your web browser at
the right page; if not, you can manually visit the specified port in
your web browser.
## Using pprof with Linux Perf
pprof can read `perf.data` files generated by the
@@ -29,7 +29,40 @@ location. pprof is agnostic to the profile semantics, so other uses are
possible. The interpretation of the reports generated by pprof depends on the
semantics defined by the source of the profile.
# General usage
# Usage Modes
There are few different ways of using `pprof`.
## Report generation
If a report format is requested on the command line:
pprof <format> [options] source
pprof will generate a report in the specified format and exit.
Formats can be either text, or graphical. See below for details about
supported formats, options, and sources.
## Interactive terminal use
Without a format specifier:
pprof [options] source
pprof will start an interactive shell in which the user can type
commands. Type `help` to get online help.
## Web interface
If a port is specified on the command line:
pprof -http=<port> [options] source
pprof will start serving HTTP requests on the specified port. Visit
the HTTP url corresponding to the port (typically `http://localhost:<port>/`)
in a browser to see the interface.
# Details
The objective of pprof is to generate a report for a profile. The report is
generated from a location hierarchy, which is reconstructed from the profile
@@ -38,14 +71,12 @@ itself, while *cum* is the value of the location plus all its
descendants. Samples that include a location multiple times (eg for recursive
functions) are counted only once per location.
The basic usage of pprof is
pprof <format> [options] source
## Options
Where *format* selects the nature of the report, and *options* configure the
contents of the report. Each option has a value, which can be boolean, numeric,
or strings. While only one format can be specified, most options can be selected
independently of each other.
*options* configure the contents of a report. Each option has a value,
which can be boolean, numeric, or strings. While only one format can
be specified, most options can be selected independently of each
other.
Some common pprof options are:
@@ -32,6 +32,7 @@ type source struct {
Seconds int
Timeout int
Symbolize string
HTTPPort int
}
// Parse parses the command lines through the specified flags package
@@ -58,6 +59,7 @@ func parseFlags(o *plugin.Options) (*source, []string, error) {
flagTools := flag.String("tools", os.Getenv("PPROF_TOOLS"), "Path for object tool pathnames")
flagTimeout := flag.Int("timeout", -1, "Timeout in seconds for fetching a profile")
flagHTTPPort := flag.Int("http", 0, "Present interactive web based UI at the specified http port")
// Flags used during command processing
installedFlags := installFlags(flag)
@@ -106,6 +108,9 @@ func parseFlags(o *plugin.Options) (*source, []string, error) {
if err != nil {
return nil, nil, err
}
if cmd != nil && *flagHTTPPort != 0 {
return nil, nil, fmt.Errorf("--http is not compatible with an output format on the command line")
}
si := pprofVariables["sample_index"].value
si = sampleIndex(flagTotalDelay, si, "delay", "-total_delay", o.UI)
@@ -128,6 +133,7 @@ func parseFlags(o *plugin.Options) (*source, []string, error) {
Seconds: *flagSeconds,
Timeout: *flagTimeout,
Symbolize: *flagSymbolize,
HTTPPort: *flagHTTPPort,
}
for _, s := range *flagBase {
@@ -240,7 +246,25 @@ func outputFormat(bcmd map[string]*bool, acmd map[string]*string) (cmd []string,
return cmd, nil
}
var usageMsgHdr = "usage: pprof [options] [-base source] [binary] <source> ...\n"
var usageMsgHdr = `usage:
Produce output in the specified format.
pprof <format> [options] [binary] <source> ...
Omit the format to get an interactive shell whose commands can be used
to generate various views of a profile
pprof [options] [binary] <source> ...
Omit the format and provide the "-http" flag to get an interactive web
interface at the specified port that can be used to navigate through
various views of a profile.
pprof -http <port> [options] [binary] <source> ...
Details:
`
var usageMsgSrc = "\n\n" +
" Source options:\n" +
@@ -261,6 +285,7 @@ var usageMsgSrc = "\n\n" +
var usageMsgVars = "\n\n" +
" Misc options:\n" +
" -http port Provide web based interface at port\n" +
" -tools Search path for object tools\n" +
"\n" +
" Environment Variables:\n" +
@@ -263,7 +263,7 @@ func usage(commandLine bool) string {
var help string
if commandLine {
help = " Output formats (select only one):\n"
help = " Output formats (select at most one):\n"
} else {
help = " Commands:\n"
commands = append(commands, fmtHelp("o/options", "List options and their current values"))
@@ -52,10 +52,13 @@ func PProf(eo *plugin.Options) error {
return generateReport(p, cmd, pprofVariables, o)
}
if src.HTTPPort > 0 {
return serveWebInterface(src.HTTPPort, p, o)
}
return interactive(p, o)
}
func generateReport(p *profile.Profile, cmd []string, vars variables, o *plugin.Options) error {
func generateRawReport(p *profile.Profile, cmd []string, vars variables, o *plugin.Options) (*command, *report.Report, error) {
p = p.Copy() // Prevent modification to the incoming profile.
vars = applyCommandOverrides(cmd, vars)
@@ -64,12 +67,12 @@ func generateReport(p *profile.Profile, cmd []string, vars variables, o *plugin.
relative := vars["relative_percentages"].boolValue()
if relative {
if err := applyFocus(p, vars, o.UI); err != nil {
return err
return nil, nil, err
}
}
ropt, err := reportOptions(p, vars)
if err != nil {
return err
return nil, nil, err
}
c := pprofCommands[cmd[0]]
if c == nil {
@@ -79,18 +82,27 @@ func generateReport(p *profile.Profile, cmd []string, vars variables, o *plugin.
if len(cmd) == 2 {
s, err := regexp.Compile(cmd[1])
if err != nil {
return fmt.Errorf("parsing argument regexp %s: %v", cmd[1], err)
return nil, nil, fmt.Errorf("parsing argument regexp %s: %v", cmd[1], err)
}
ropt.Symbol = s
}
rpt := report.New(p, ropt)
if !relative {
if err := applyFocus(p, vars, o.UI); err != nil {
return err
return nil, nil, err
}
}
if err := aggregate(p, vars); err != nil {
return nil, nil, err
}
return c, rpt, nil
}
func generateReport(p *profile.Profile, cmd []string, vars variables, o *plugin.Options) error {
c, rpt, err := generateRawReport(p, cmd, vars, o)
if err != nil {
return err
}
Oops, something went wrong.

0 comments on commit f83a3d8

Please sign in to comment.