* **-text:** Prints the location entries, one per line, including the flat and cum
values.
-* **-tree:** Prints each location entry with its predecessors and successors.
+* **-tree:** Prints each location entry with its predecessors and successors.
* **-peek= _regex_:** Print the location entry with all its predecessors and
successors, without trimming any entries.
* **-traces:** Prints each sample with a location per line.
pprof will look for source files on its current working directory and all its
ancestors. pprof will look for binaries on the directories specified in the
-`$PPROF_BINARY_PATH` environment variable, by default `$HOME/pprof/binaries`. It
-will look binaries up by name, and if the profile includes linker build ids, it
-will also search for them in a directory named as the build id.
+`$PPROF_BINARY_PATH` environment variable, by default `$HOME/pprof/binaries`
+(`%USERPROFILE%\pprof\binaries` on Windows). It will look binaries up by name,
+and if the profile includes linker build ids, it will also search for them in
+a directory named as the build id.
pprof uses the binutils tools to examine and disassemble the binaries. By
default it will search for those tools in the current path, but it can also
sym = &internalSymbolizer{o.Sym}
}
return &plugin.Options{
- o.Writer,
- o.Flagset,
- o.Fetch,
- sym,
- obj,
- o.UI,
+ Writer: o.Writer,
+ Flagset: o.Flagset,
+ Fetch: o.Fetch,
+ Sym: sym,
+ Obj: obj,
+ UI: o.UI,
}
}
}
}
- return plugin.Frame{funcname, fileline, linenumber}, false
+ return plugin.Frame{
+ Func: funcname,
+ File: fileline,
+ Line: linenumber}, false
}
// addrInfo returns the stack frame information for a specific program
fileline, err := d.readString()
if err != nil {
- return plugin.Frame{funcname, "", 0}, true
+ return plugin.Frame{Func: funcname}, true
}
linenumber := 0
}
}
- return plugin.Frame{funcname, fileline, linenumber}, false
+ return plugin.Frame{Func: funcname, File: fileline, Line: linenumber}, false
}
// addrInfo returns the stack frame information for a specific program
}
for l, f := range s {
level := (len(s) - l) * 1000
- want := plugin.Frame{functionName(level), fmt.Sprintf("file%d", level), level}
+ want := plugin.Frame{Func: functionName(level), File: fmt.Sprintf("file%d", level), Line: level}
if f != want {
t.Errorf("AddrInfo(%#x)[%d]: = %+v, want %+v", addr, l, f, want)
continue
}
if match := matchSymbol(names, start, symAddr-1, r, address); match != nil {
- symbols = append(symbols, &plugin.Sym{match, file, start, symAddr - 1})
+ symbols = append(symbols, &plugin.Sym{Name: match, File: file, Start: start, End: symAddr - 1})
}
names, start = []string{name}, symAddr
}
"line.*[AC]",
testsyms,
[]plugin.Sym{
- {[]string{"lineA001"}, "object.o", 0x1000, 0x1FFF},
- {[]string{"line200A"}, "object.o", 0x2000, 0x2FFF},
- {[]string{"lineB00C"}, "object.o", 0x3000, 0x3FFF},
+ {Name: []string{"lineA001"}, File: "object.o", Start: 0x1000, End: 0x1FFF},
+ {Name: []string{"line200A"}, File: "object.o", Start: 0x2000, End: 0x2FFF},
+ {Name: []string{"lineB00C"}, File: "object.o", Start: 0x3000, End: 0x3FFF},
},
},
{
"Dumb::operator",
testsyms,
[]plugin.Sym{
- {[]string{"Dumb::operator()(char const*) const"}, "object.o", 0x3000, 0x3FFF},
+ {Name: []string{"Dumb::operator()(char const*) const"}, File: "object.o", Start: 0x3000, End: 0x3FFF},
},
},
}
}
testcases := []testcase{
{
- plugin.Sym{[]string{"symbol1"}, "", 0x1000, 0x1FFF},
+ plugin.Sym{Name: []string{"symbol1"}, Start: 0x1000, End: 0x1FFF},
` 1000: instruction one
1001: instruction two
1002: instruction three
},
},
{
- plugin.Sym{[]string{"symbol2"}, "", 0x2000, 0x2FFF},
+ plugin.Sym{Name: []string{"symbol2"}, Start: 0x2000, End: 0x2FFF},
` 2000: instruction one
2001: instruction two
`,
" PPROF_TOOLS Search path for object-level tools\n" +
" PPROF_BINARY_PATH Search path for local binary files\n" +
" default: $HOME/pprof/binaries\n" +
- " finds binaries by $name and $buildid/$name\n"
+ " finds binaries by $name and $buildid/$name\n" +
+ " * On Windows, %USERPROFILE% is used instead of $HOME"
"os"
"os/exec"
"path/filepath"
+ "runtime"
"strconv"
"strings"
"sync"
err error
}
+func homeEnv() string {
+ switch runtime.GOOS {
+ case "windows":
+ return "USERPROFILE"
+ case "plan9":
+ return "home"
+ default:
+ return "HOME"
+ }
+}
+
// setTmpDir prepares the directory to use to save profiles retrieved
// remotely. It is selected from PPROF_TMPDIR, defaults to $HOME/pprof.
func setTmpDir(ui plugin.UI) (string, error) {
if profileDir := os.Getenv("PPROF_TMPDIR"); profileDir != "" {
return profileDir, nil
}
- for _, tmpDir := range []string{os.Getenv("HOME") + "/pprof", os.TempDir()} {
+ for _, tmpDir := range []string{os.Getenv(homeEnv()) + "/pprof", os.TempDir()} {
if err := os.MkdirAll(tmpDir, 0755); err != nil {
ui.PrintErr("Could not use temp dir ", tmpDir, ": ", err.Error())
continue
searchPath := os.Getenv("PPROF_BINARY_PATH")
if searchPath == "" {
// Use $HOME/pprof/binaries as default directory for local symbolization binaries
- searchPath = filepath.Join(os.Getenv("HOME"), "pprof", "binaries")
+ searchPath = filepath.Join(os.Getenv(homeEnv()), "pprof", "binaries")
}
mapping:
for _, m := range p.Mapping {
fileNames = append(fileNames, matches...)
}
}
- if baseName != "" {
- fileNames = append(fileNames, filepath.Join(path, baseName))
+ if m.File != "" {
+ // Try both the basename and the full path, to support the same directory
+ // structure as the perf symfs option.
+ if baseName != "" {
+ fileNames = append(fileNames, filepath.Join(path, baseName))
+ }
+ fileNames = append(fileNames, filepath.Join(path, m.File))
}
for _, name := range fileNames {
if f, err := obj.Open(name, m.Start, m.Limit, m.Offset); err == nil {
}{
{"", "/usr/bin/binary", "", "/usr/bin/binary", 0},
{"", "/usr/bin/binary", "fedcb10000", "/usr/bin/binary", 0},
+ {"/usr", "/bin/binary", "", "/usr/bin/binary", 0},
{"", "/prod/path/binary", "abcde10001", filepath.Join(tempdir, "pprof/binaries/abcde10001/binary"), 0},
{"/alternate/architecture", "/usr/bin/binary", "", "/alternate/architecture/binary", 0},
{"/alternate/architecture", "/usr/bin/binary", "abcde10001", "/alternate/architecture/binary", 0},
}
got := collectMappingSources(p, url)
if !reflect.DeepEqual(got, tc.want) {
- t.Errorf("%s:%s, want %s, got %s", tc.file, tc.buildID, tc.want, got)
+ t.Errorf("%s:%s, want %v, got %v", tc.file, tc.buildID, tc.want, got)
}
}
}
d.UI = &stdUI{r: bufio.NewReader(os.Stdin)}
}
if d.Sym == nil {
- d.Sym = &symbolizer.Symbolizer{d.Obj, d.UI}
+ d.Sym = &symbolizer.Symbolizer{Obj: d.Obj, UI: d.UI}
}
return d
}
sibling: "sibling",
}
- g := &graph.Graph{n}
+ g := &graph.Graph{Nodes: n}
names := getDisambiguatedNames(g)
}
var mockAddresses = map[uint64][]plugin.Frame{
- 1000: []plugin.Frame{{"fun11", "file11.src", 10}},
- 2000: []plugin.Frame{{"fun21", "file21.src", 20}, {"fun22", "file22.src", 20}},
- 3000: []plugin.Frame{{"fun31", "file31.src", 30}, {"fun32", "file32.src", 30}, {"fun33", "file33.src", 30}},
- 4000: []plugin.Frame{{"fun41", "file41.src", 40}, {"fun42", "file42.src", 40}, {"fun43", "file43.src", 40}, {"fun44", "file44.src", 40}},
- 5000: []plugin.Frame{{"fun51", "file51.src", 50}, {"fun52", "file52.src", 50}, {"fun53", "file53.src", 50}, {"fun54", "file54.src", 50}, {"fun55", "file55.src", 50}},
+ 1000: []plugin.Frame{frame("fun11", "file11.src", 10)},
+ 2000: []plugin.Frame{frame("fun21", "file21.src", 20), frame("fun22", "file22.src", 20)},
+ 3000: []plugin.Frame{frame("fun31", "file31.src", 30), frame("fun32", "file32.src", 30), frame("fun33", "file33.src", 30)},
+ 4000: []plugin.Frame{frame("fun41", "file41.src", 40), frame("fun42", "file42.src", 40), frame("fun43", "file43.src", 40), frame("fun44", "file44.src", 40)},
+ 5000: []plugin.Frame{frame("fun51", "file51.src", 50), frame("fun52", "file52.src", 50), frame("fun53", "file53.src", 50), frame("fun54", "file54.src", 50), frame("fun55", "file55.src", 50)},
+}
+
+func frame(fname, file string, line int) plugin.Frame {
+ return plugin.Frame{
+ Func: fname,
+ File: file,
+ Line: line}
}
type mockObjTool struct{}
{
"canonical": "github.com/google/pprof",
"local": "github.com/google/pprof",
- "revision": "8b5491579fe32b2af1befa740ac5e6114cbd3e56",
- "revisionTime": "2017-02-17T22:14:04Z",
+ "revision": "e41fb7133e7ebb84ba6af2f6443032c728db26d3",
+ "revisionTime": "2017-03-01T00:04:42Z",
},
{
"canonical": "golang.org/x/arch/x86/x86asm",