Skip to content

Commit

Permalink
Merge pull request #3 from google/master
Browse files Browse the repository at this point in the history
pull from remote master
  • Loading branch information
kalyanac authored May 6, 2020
2 parents 4d646c8 + 160c429 commit 5987a5e
Show file tree
Hide file tree
Showing 50 changed files with 486 additions and 291 deletions.
25 changes: 14 additions & 11 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,35 @@ go_import_path: github.com/google/pprof
matrix:
include:
- os: linux
go: 1.10.x
go: 1.13.x
- os: linux
go: 1.11.x
go: 1.14.x
- os: linux
go: master
- os: osx
osx_image: xcode8.3
go: 1.10.x
go: 1.13.x
- os: osx
osx_image: xcode8.3
go: 1.11.x
go: 1.14.x
- os: osx
osx_image: xcode8.3
go: master
- os: osx
osx_image: xcode9.4
go: 1.10.x
go: 1.13.x
- os: osx
osx_image: xcode9.4
go: 1.11.x
go: 1.14.x
- os: osx
osx_image: xcode9.4
go: master
- os: osx
osx_image: xcode10.1
go: 1.10.x
go: 1.13.x
- os: osx
osx_image: xcode10.1
go: 1.11.x
go: 1.14.x
- os: osx
osx_image: xcode10.1
go: master
Expand All @@ -46,16 +46,19 @@ addons:
packages:
- graphviz
update: true

before_install:
- go get -u golang.org/x/lint/golint honnef.co/go/tools/cmd/...
# Do not let tools interfere with the main module's go.mod
- env GO111MODULE=off go get -u golang.org/x/lint/golint honnef.co/go/tools/cmd/...

script:
- gofmtdiff=$(gofmt -s -d .) && if [ -n "$gofmtdiff" ]; then printf 'gofmt -s found:\n%s\n' "$gofmtdiff" && exit 1; fi
- golintlint=$(golint ./...) && if [ -n "$golintlint" ]; then printf 'golint found:\n%s\n' "$golintlint" && exit 1; fi
- go vet -all ./...
- gosimple ./...
- ./test.sh

# Check still works in GOPATH mode.
- env GO111MODULE=off go get -d . && go test -v ./...

after_success:
- bash <(curl -s https://codecov.io/bash)
1 change: 1 addition & 0 deletions CONTRIBUTORS
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ Tipp Moseley <tipp@google.com>
Hyoun Kyu Cho <netforce@google.com>
Martin Spier <spiermar@gmail.com>
Taco de Wolff <tacodewolff@gmail.com>
Andrew Hunter <andrewhhunter@gmail.com>
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[![Build Status](https://travis-ci.org/google/pprof.svg?branch=master)](https://travis-ci.org/google/pprof)
[![Build status](https://ci.appveyor.com/api/projects/status/ucu3k9t263f8syn3?svg=true)](https://ci.appveyor.com/project/gwpappveyor/pprof)
[![codecov](https://codecov.io/gh/google/pprof/graph/badge.svg)](https://codecov.io/gh/google/pprof)

# Introduction
Expand Down
10 changes: 5 additions & 5 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
clone_folder: c:\go\src\github.com\google\pprof
clone_folder: c:\gopath\src\github.com\google\pprof

environment:
GOPATH: c:\gopath

install:
- cinst graphviz

before_build:
- go get github.com/ianlancetaylor/demangle
- go get github.com/chzyer/readline

build_script:
- go env
- go build github.com/google/pprof

test_script:
Expand Down
115 changes: 83 additions & 32 deletions doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ text and graphical reports (through the use of the dot visualization package).
profile.proto is a protocol buffer that describes a set of callstacks
and symbolization information. A common usage is to represent a set of
sampled callstacks from statistical profiling. The format is
described on the src/proto/profile.proto file. For details on protocol
described on the proto/profile.proto file. For details on protocol
buffers, see https://developers.google.com/protocol-buffers

Profiles can be read from a local file, or over http. Multiple
Expand All @@ -24,7 +24,7 @@ pprof operates on data in the profile.proto format. Each profile is a collection
of samples, where each sample is associated to a point in a location hierarchy,
one or more numeric values, and a set of labels. Often these profiles represents
data collected through statistical sampling of a program, so each sample
describes a program call stack and a number or weight of samples collected at a
describes a program call stack and a number or value of samples collected at a
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.
Expand Down Expand Up @@ -66,10 +66,13 @@ in a browser to see the interface.

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
samples. Each location contains two values: *flat* is the value of the location
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.
samples. Each location contains two values:

* *flat*: the value of the location itself.
* *cum*: the value of the location plus all its descendants.

Samples that include a location multiple times (e.g. for recursive functions)
are counted only once per location.

## Options

Expand All @@ -81,19 +84,20 @@ other.
Some common pprof options are:

* **-flat** [default], **-cum**: Sort entries based on their flat or cumulative
weight respectively, on text reports.
value respectively, on text reports.
* **-functions** [default], **-filefunctions**, **-files**, **-lines**,
**-addresses**: Generate the report using the specified granularity.
* **-noinlines**: Attribute inlined functions to their first out-of-line caller.
For example, a command like `pprof -list foo -noinlines profile.pb.gz` can be
used to produce the annotated source listing attributing the metrics in the
inlined functions to the out-of-line calling line.
* **-nodecount= _int_:** Maximum number of entries in the report. pprof will only print
this many entries and will use heuristics to select which entries to trim.
* **-nodecount= _int_:** Maximum number of entries in the report. pprof will
only print this many entries and will use heuristics to select which entries
to trim.
* **-focus= _regex_:** Only include samples that include a report entry matching
*regex*.
* **-ignore= _regex_:** Do not include samples that include a report entry matching
*regex*.
* **-ignore= _regex_:** Do not include samples that include a report entry
matching *regex*.
* **-show\_from= _regex_:** Do not show entries above the first one that
matches *regex*.
* **-show= _regex_:** Only show entries that match *regex*.
Expand Down Expand Up @@ -161,8 +165,8 @@ range) match a given sample, then the sample will be discarded.

pprof text reports show the location hierarchy in text format.

* **-text:** Prints the location entries, one per line, including the flat and cum
values.
* **-text:** Prints the location entries, one per line, including the flat and
cum values.
* **-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.
Expand All @@ -174,23 +178,70 @@ pprof can generate graphical reports on the DOT format, and convert them to
multiple formats using the graphviz package.

These reports represent the location hierarchy as a graph, with a report entry
represented as a node. Solid edges represent a direct connection between
entries, while dotted edges represent a connection where some intermediate nodes
have been removed. Nodes are removed using heuristics to limit the size of
represented as a node. Nodes are removed using heuristics to limit the size of
the graph, controlled by the *nodecount* option.

The size of each node represents the flat weight of the node, and the width of
each edge represents the cumulative weight of all samples going through
it. Nodes are colored according to their cumulative weight, highlighting the
paths with the highest cum weight.

* **-dot:** Generates a report in .dot format. All other formats are generated from
this one.
* **-dot:** Generates a report in .dot format. All other formats are generated
from this one.
* **-svg:** Generates a report in SVG format.
* **-web:** Generates a report in SVG format on a temp file, and starts a web
browser to view it.
* **-png, -jpg, -gif, -pdf:** Generates a report in these formats,

* **-png, -jpg, -gif, -pdf:** Generates a report in these formats.

### Interpreting the Callgraph

* **Node Color**:
* large positive cum values are red.
* large negative cum values are green.
* cum values close to zero are grey.

* **Node Font Size**:
* larger font size means larger absolute flat values.
* smaller font size means smaller absolute flat values.

* **Edge Weight**:
* thicker edges indicate more resources were used along that path.
* thinner edges indicate fewer resources were used along that path.

* **Edge Color**:
* large positive values are red.
* large negative values are green.
* values close to zero are grey.

* **Dashed Edges**: some locations between the two connected locations were
removed.

* **Solid Edges**: one location directly calls the other.

* **"(inline)" Edge Marker**: the call has been inlined into the caller.

Let's consider the following example graph:

![callgraph](images/callgraph.png)

* For nodes:
* `(*Rand).Read` has a small flat value and a small cum value because the
the font is small and the node is grey.
* `(*compressor).deflate` has a large flat value and a large cum value because the font
is large and the node is red.
* `(*Writer).Flush` has a small flat value and a large cum value because the font is
small and the node is red.

* For edges:
* the edge between `(*Writer).Write` and `(*compressor).write`:
* Since it is a dashed edge, some nodes were removed between those two.
* Since it is thick and red, more resources were used in call stacks between
those two nodes.
* the edge between `(*Rand).Read` and `read`:
* Since it is a dashed edge, some nodes were removed between those two.
* Since it is thin and grey, fewer resources were used in call stacks
between those two nodes.
* the edge between `read` and `(*rngSource).Int63`:
* Since it is a solid edge, there are no nodes between those two (i.e. it
was a direct call).
* Since it is thin and grey, fewer resrouces were used in call stacks
between those two nodes.

## Annotated code

pprof can also generate reports of annotated source with samples associated to
Expand All @@ -210,7 +261,7 @@ search for them in a directory pointed to by the environment variable
`$PPROF_TOOLS`.

* **-list= _regex_:** Generates an annotated source listing for functions
matching *regex*, with flat/cum weights for each source line.
matching *regex*, with flat/cum values for each source line.
* **-disasm= _regex_:** Generates an annotated disassembly listing for
functions matching *regex*.
* **-weblist= _regex_:** Generates a source/assembly combined annotated listing
Expand Down Expand Up @@ -264,12 +315,12 @@ also accept some legacy formats generated by
When fetching from a URL handler, pprof accepts options to indicate how much to
wait for the profile.

* **-seconds= _int_:** Makes pprof request for a profile with the specified duration
in seconds. Only makes sense for profiles based on elapsed time, such as CPU
profiles.
* **-timeout= _int_:** Makes pprof wait for the specified timeout when retrieving a
profile over http. If not specified, pprof will use heuristics to determine a
reasonable timeout.
* **-seconds= _int_:** Makes pprof request for a profile with the specified
duration in seconds. Only makes sense for profiles based on elapsed time, such
as CPU profiles.
* **-timeout= _int_:** Makes pprof wait for the specified timeout when
retrieving a profile over http. If not specified, pprof will use heuristics to
determine a reasonable timeout.

pprof also accepts options which allow a user to specify TLS certificates to
use when fetching or symbolizing a profile from a protected endpoint. For more
Expand Down
Binary file added doc/images/callgraph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 3 additions & 10 deletions driver/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,6 @@ type FlagSet interface {
Float64(name string, def float64, usage string) *float64
String(name string, def string, usage string) *string

// BoolVar, IntVar, Float64Var, and StringVar define new flags referencing
// a given pointer, like the functions of the same name in package flag.
BoolVar(pointer *bool, name string, def bool, usage string)
IntVar(pointer *int, name string, def int, usage string)
Float64Var(pointer *float64, name string, def float64, usage string)
StringVar(pointer *string, name string, def string, usage string)

// StringList is similar to String but allows multiple values for a
// single flag
StringList(name string, def string, usage string) *[]*string
Expand Down Expand Up @@ -149,7 +142,7 @@ type ObjTool interface {

// Disasm disassembles the named object file, starting at
// the start address and stopping at (before) the end address.
Disasm(file string, start, end uint64) ([]Inst, error)
Disasm(file string, start, end uint64, intelSyntax bool) ([]Inst, error)
}

// An Inst is a single instruction in an assembly listing.
Expand Down Expand Up @@ -276,8 +269,8 @@ func (f *internalObjFile) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym,
return pluginSyms, nil
}

func (o *internalObjTool) Disasm(file string, start, end uint64) ([]plugin.Inst, error) {
insts, err := o.ObjTool.Disasm(file, start, end)
func (o *internalObjTool) Disasm(file string, start, end uint64, intelSyntax bool) ([]plugin.Inst, error) {
insts, err := o.ObjTool.Disasm(file, start, end, intelSyntax)
if err != nil {
return nil, err
}
Expand Down
11 changes: 11 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module github.com/google/pprof

go 1.14

require (
github.com/chzyer/logex v1.1.10 // indirect
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e // indirect
)
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e h1:9vRrk9YW2BTzLP0VCB9ZDjU4cPqkg+IDWL7XgxA1yxQ=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
18 changes: 14 additions & 4 deletions internal/binutils/binutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,22 @@ func findExe(cmd string, paths []string) (string, bool) {

// Disasm returns the assembly instructions for the specified address range
// of a binary.
func (bu *Binutils) Disasm(file string, start, end uint64) ([]plugin.Inst, error) {
func (bu *Binutils) Disasm(file string, start, end uint64, intelSyntax bool) ([]plugin.Inst, error) {
b := bu.get()
cmd := exec.Command(b.objdump, "-d", "-C", "--no-show-raw-insn", "-l",
args := []string{"-d", "-C", "--no-show-raw-insn", "-l",
fmt.Sprintf("--start-address=%#x", start),
fmt.Sprintf("--stop-address=%#x", end),
file)
fmt.Sprintf("--stop-address=%#x", end)}

if intelSyntax {
if runtime.GOOS == "darwin" {
args = append(args, "-x86-asm-syntax=intel")
} else {
args = append(args, "-M", "intel")
}
}

args = append(args, file)
cmd := exec.Command(b.objdump, args...)
out, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("%v: %v", cmd.Args, err)
Expand Down
11 changes: 8 additions & 3 deletions internal/binutils/binutils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,9 @@ func skipUnlessDarwinAmd64(t *testing.T) {
}
}

func TestDisasm(t *testing.T) {
skipUnlessLinuxAmd64(t)
func testDisasm(t *testing.T, intelSyntax bool) {
bu := &Binutils{}
insts, err := bu.Disasm(filepath.Join("testdata", "exe_linux_64"), 0, math.MaxUint64)
insts, err := bu.Disasm(filepath.Join("testdata", "exe_linux_64"), 0, math.MaxUint64, intelSyntax)
if err != nil {
t.Fatalf("Disasm: unexpected error %v", err)
}
Expand All @@ -206,6 +205,12 @@ func TestDisasm(t *testing.T) {
}
}

func TestDisasm(t *testing.T) {
skipUnlessLinuxAmd64(t)
testDisasm(t, true)
testDisasm(t, false)
}

func findSymbol(syms []*plugin.Sym, name string) *plugin.Sym {
for _, s := range syms {
for _, n := range s.Name {
Expand Down
Loading

0 comments on commit 5987a5e

Please sign in to comment.