aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go
diff options
context:
space:
mode:
authorAlberto Donizetti <alb.donizetti@gmail.com>2017-08-20 12:27:32 +0200
committerBrad Fitzpatrick <bradfitz@golang.org>2017-11-02 23:51:45 +0000
commitaec345d638fa624f08b7d758e9e173897edc80e8 (patch)
treed782d951af4f34de34a08c4775a37f869af25b81 /src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go
parent3039bff9d07ce05dc9af8c155c6929ae5e53a231 (diff)
downloadgo-aec345d638fa624f08b7d758e9e173897edc80e8.tar.xz
cmd/vendor/github.com/google/pprof: refresh from upstream
Update vendored pprof to commit 4fc39a00b6b8c1aad05260f01429ec70e127252c from github.com/google/pprof (2017-11-01). Fixes #19380 Updates #21047 Change-Id: Ib64a94a45209039e5945acbcfa0392790c8ee41e Reviewed-on: https://go-review.googlesource.com/57370 Run-TryBot: Alberto Donizetti <alb.donizetti@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go')
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go126
1 files changed, 95 insertions, 31 deletions
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 f9e8231419..2b1d90dafd 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
@@ -41,39 +41,52 @@ import (
// there are some failures. It will return an error if it is unable to
// fetch any profiles.
func fetchProfiles(s *source, o *plugin.Options) (*profile.Profile, error) {
- sources := make([]profileSource, 0, len(s.Sources)+len(s.Base))
+ sources := make([]profileSource, 0, len(s.Sources))
for _, src := range s.Sources {
sources = append(sources, profileSource{
addr: src,
source: s,
- scale: 1,
})
}
+
+ bases := make([]profileSource, 0, len(s.Base))
for _, src := range s.Base {
- sources = append(sources, profileSource{
+ bases = append(bases, profileSource{
addr: src,
source: s,
- scale: -1,
})
}
- p, msrcs, save, cnt, err := chunkedGrab(sources, o.Fetch, o.Obj, o.UI)
+
+ p, pbase, m, mbase, save, err := grabSourcesAndBases(sources, bases, o.Fetch, o.Obj, o.UI)
if err != nil {
return nil, err
}
- if cnt == 0 {
- return nil, fmt.Errorf("failed to fetch any profiles")
- }
- if want, got := len(sources), cnt; want != got {
- o.UI.PrintErr(fmt.Sprintf("fetched %d profiles out of %d", got, want))
+
+ if pbase != nil {
+ if s.Normalize {
+ err := p.Normalize(pbase)
+ if err != nil {
+ return nil, err
+ }
+ }
+ pbase.Scale(-1)
+ p, m, err = combineProfiles([]*profile.Profile{p, pbase}, []plugin.MappingSources{m, mbase})
+ if err != nil {
+ return nil, err
+ }
}
// Symbolize the merged profile.
- if err := o.Sym.Symbolize(s.Symbolize, msrcs, p); err != nil {
+ if err := o.Sym.Symbolize(s.Symbolize, m, p); err != nil {
return nil, err
}
p.RemoveUninteresting()
unsourceMappings(p)
+ if s.Comment != "" {
+ p.Comments = append(p.Comments, s.Comment)
+ }
+
// Save a copy of the merged profile if there is at least one remote source.
if save {
dir, err := setTmpDir(o.UI)
@@ -107,6 +120,47 @@ func fetchProfiles(s *source, o *plugin.Options) (*profile.Profile, error) {
return p, nil
}
+func grabSourcesAndBases(sources, bases []profileSource, fetch plugin.Fetcher, obj plugin.ObjTool, ui plugin.UI) (*profile.Profile, *profile.Profile, plugin.MappingSources, plugin.MappingSources, bool, error) {
+ wg := sync.WaitGroup{}
+ wg.Add(2)
+ var psrc, pbase *profile.Profile
+ var msrc, mbase plugin.MappingSources
+ var savesrc, savebase bool
+ var errsrc, errbase error
+ var countsrc, countbase int
+ go func() {
+ defer wg.Done()
+ psrc, msrc, savesrc, countsrc, errsrc = chunkedGrab(sources, fetch, obj, ui)
+ }()
+ go func() {
+ defer wg.Done()
+ pbase, mbase, savebase, countbase, errbase = chunkedGrab(bases, fetch, obj, ui)
+ }()
+ wg.Wait()
+ save := savesrc || savebase
+
+ if errsrc != nil {
+ return nil, nil, nil, nil, false, fmt.Errorf("problem fetching source profiles: %v", errsrc)
+ }
+ if errbase != nil {
+ return nil, nil, nil, nil, false, fmt.Errorf("problem fetching base profiles: %v,", errbase)
+ }
+ if countsrc == 0 {
+ return nil, nil, nil, nil, false, fmt.Errorf("failed to fetch any source profiles")
+ }
+ if countbase == 0 && len(bases) > 0 {
+ return nil, nil, nil, nil, false, fmt.Errorf("failed to fetch any base profiles")
+ }
+ if want, got := len(sources), countsrc; want != got {
+ ui.PrintErr(fmt.Sprintf("Fetched %d source profiles out of %d", got, want))
+ }
+ if want, got := len(bases), countbase; want != got {
+ ui.PrintErr(fmt.Sprintf("Fetched %d base profiles out of %d", got, want))
+ }
+
+ return psrc, pbase, msrc, mbase, save, nil
+}
+
// chunkedGrab fetches the profiles described in source and merges them into
// a single profile. It fetches a chunk of profiles concurrently, with a maximum
// chunk size to limit its memory usage.
@@ -142,6 +196,7 @@ func chunkedGrab(sources []profileSource, fetch plugin.Fetcher, obj plugin.ObjTo
count += chunkCount
}
}
+
return p, msrc, save, count, nil
}
@@ -152,7 +207,7 @@ func concurrentGrab(sources []profileSource, fetch plugin.Fetcher, obj plugin.Ob
for i := range sources {
go func(s *profileSource) {
defer wg.Done()
- s.p, s.msrc, s.remote, s.err = grabProfile(s.source, s.addr, s.scale, fetch, obj, ui)
+ s.p, s.msrc, s.remote, s.err = grabProfile(s.source, s.addr, fetch, obj, ui)
}(&sources[i])
}
wg.Wait()
@@ -207,7 +262,6 @@ func combineProfiles(profiles []*profile.Profile, msrcs []plugin.MappingSources)
type profileSource struct {
addr string
source *source
- scale float64
p *profile.Profile
msrc plugin.MappingSources
@@ -227,12 +281,18 @@ func homeEnv() string {
}
// setTmpDir prepares the directory to use to save profiles retrieved
-// remotely. It is selected from PPROF_TMPDIR, defaults to $HOME/pprof.
+// remotely. It is selected from PPROF_TMPDIR, defaults to $HOME/pprof, and, if
+// $HOME is not set, falls back to os.TempDir().
func setTmpDir(ui plugin.UI) (string, error) {
+ var dirs []string
if profileDir := os.Getenv("PPROF_TMPDIR"); profileDir != "" {
- return profileDir, nil
+ dirs = append(dirs, profileDir)
}
- for _, tmpDir := range []string{os.Getenv(homeEnv()) + "/pprof", os.TempDir()} {
+ if homeDir := os.Getenv(homeEnv()); homeDir != "" {
+ dirs = append(dirs, filepath.Join(homeDir, "pprof"))
+ }
+ dirs = append(dirs, os.TempDir())
+ for _, tmpDir := range dirs {
if err := os.MkdirAll(tmpDir, 0755); err != nil {
ui.PrintErr("Could not use temp dir ", tmpDir, ": ", err.Error())
continue
@@ -242,10 +302,12 @@ func setTmpDir(ui plugin.UI) (string, error) {
return "", fmt.Errorf("failed to identify temp dir")
}
+const testSourceAddress = "pproftest.local"
+
// grabProfile fetches a profile. Returns the profile, sources for the
// profile mappings, a bool indicating if the profile was fetched
// remotely, and an error.
-func grabProfile(s *source, source string, scale float64, fetcher plugin.Fetcher, obj plugin.ObjTool, ui plugin.UI) (p *profile.Profile, msrc plugin.MappingSources, remote bool, err error) {
+func grabProfile(s *source, source string, fetcher plugin.Fetcher, obj plugin.ObjTool, ui plugin.UI) (p *profile.Profile, msrc plugin.MappingSources, remote bool, err error) {
var src string
duration, timeout := time.Duration(s.Seconds)*time.Second, time.Duration(s.Timeout)*time.Second
if fetcher != nil {
@@ -266,9 +328,6 @@ func grabProfile(s *source, source string, scale float64, fetcher plugin.Fetcher
return
}
- // Apply local changes to the profile.
- p.Scale(scale)
-
// Update the binary locations from command line and paths.
locateBinaries(p, s, obj, ui)
@@ -276,6 +335,11 @@ func grabProfile(s *source, source string, scale float64, fetcher plugin.Fetcher
if src != "" {
msrc = collectMappingSources(p, src)
remote = true
+ if strings.HasPrefix(src, "http://"+testSourceAddress) {
+ // Treat test inputs as local to avoid saving
+ // testcase profiles during driver testing.
+ remote = false
+ }
}
return
}
@@ -366,20 +430,20 @@ mapping:
}
}
}
+ if len(p.Mapping) == 0 {
+ // If there are no mappings, add a fake mapping to attempt symbolization.
+ // This is useful for some profiles generated by the golang runtime, which
+ // do not include any mappings. Symbolization with a fake mapping will only
+ // be successful against a non-PIE binary.
+ m := &profile.Mapping{ID: 1}
+ p.Mapping = []*profile.Mapping{m}
+ for _, l := range p.Location {
+ l.Mapping = m
+ }
+ }
// Replace executable filename/buildID with the overrides from source.
// Assumes the executable is the first Mapping entry.
if execName, buildID := s.ExecName, s.BuildID; execName != "" || buildID != "" {
- if len(p.Mapping) == 0 {
- // If there are no mappings, add a fake mapping to attempt symbolization.
- // This is useful for some profiles generated by the golang runtime, which
- // do not include any mappings. Symbolization with a fake mapping will only
- // be successful against a non-PIE binary.
- m := &profile.Mapping{ID: 1}
- p.Mapping = []*profile.Mapping{m}
- for _, l := range p.Location {
- l.Mapping = m
- }
- }
m := p.Mapping[0]
if execName != "" {
m.File = execName