diff options
| author | Alberto Donizetti <alb.donizetti@gmail.com> | 2017-08-20 12:27:32 +0200 |
|---|---|---|
| committer | Brad Fitzpatrick <bradfitz@golang.org> | 2017-11-02 23:51:45 +0000 |
| commit | aec345d638fa624f08b7d758e9e173897edc80e8 (patch) | |
| tree | d782d951af4f34de34a08c4775a37f869af25b81 /src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go | |
| parent | 3039bff9d07ce05dc9af8c155c6929ae5e53a231 (diff) | |
| download | go-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.go | 126 |
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 |
