aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/vendor/github.com/google/pprof/profile
diff options
context:
space:
mode:
authorDaniel Martí <mvdan@mvdan.cc>2018-02-12 16:34:48 +0000
committerDaniel Martí <mvdan@mvdan.cc>2018-02-15 16:25:43 +0000
commite7cbbbe9bb878b6ca4ce04fde645df1c8f1845bd (patch)
treef84255198234eb4870c48228cdb4828de1f4f8c5 /src/cmd/vendor/github.com/google/pprof/profile
parentafb9fc1de922a4ead9d2d787613255a7ba3490f7 (diff)
downloadgo-e7cbbbe9bb878b6ca4ce04fde645df1c8f1845bd.tar.xz
cmd/vendor/github.com/google/pprof: refresh from upstream
Updating to commit 0e0e5b7254e076a62326ab7305ba49e8515f0c91 from github.com/google/pprof Recent modifications to the vendored pprof, such as skipping TestWebInterface to avoid starting a web browser, have all been fixed upstream. Change-Id: I72e11108c438e1573bf2f9216e76d157378e8d45 Reviewed-on: https://go-review.googlesource.com/93375 Run-TryBot: Daniel Martí <mvdan@mvdan.cc> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Diffstat (limited to 'src/cmd/vendor/github.com/google/pprof/profile')
-rw-r--r--src/cmd/vendor/github.com/google/pprof/profile/encode.go9
-rw-r--r--src/cmd/vendor/github.com/google/pprof/profile/merge.go23
-rw-r--r--src/cmd/vendor/github.com/google/pprof/profile/profile.go15
-rw-r--r--src/cmd/vendor/github.com/google/pprof/profile/profile_test.go147
-rw-r--r--src/cmd/vendor/github.com/google/pprof/profile/proto_test.go24
5 files changed, 199 insertions, 19 deletions
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/encode.go b/src/cmd/vendor/github.com/google/pprof/profile/encode.go
index 622319484a..1e84c72d43 100644
--- a/src/cmd/vendor/github.com/google/pprof/profile/encode.go
+++ b/src/cmd/vendor/github.com/google/pprof/profile/encode.go
@@ -214,7 +214,12 @@ var profileDecoder = []decoder{
// int64 keep_frames = 8
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).keepFramesX) },
// int64 time_nanos = 9
- func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).TimeNanos) },
+ func(b *buffer, m message) error {
+ if m.(*Profile).TimeNanos != 0 {
+ return errConcatProfile
+ }
+ return decodeInt64(b, &m.(*Profile).TimeNanos)
+ },
// int64 duration_nanos = 10
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).DurationNanos) },
// ValueType period_type = 11
@@ -480,6 +485,7 @@ func (p *Location) encode(b *buffer) {
for i := range p.Line {
encodeMessage(b, 4, &p.Line[i])
}
+ encodeBoolOpt(b, 5, p.IsFolded)
}
var locationDecoder = []decoder{
@@ -493,6 +499,7 @@ var locationDecoder = []decoder{
pp.Line = append(pp.Line, Line{})
return decodeMessage(b, &pp.Line[n])
},
+ func(b *buffer, m message) error { return decodeBool(b, &m.(*Location).IsFolded) }, // optional bool is_folded = 5;
}
func (p *Line) decoder() []decoder {
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/merge.go b/src/cmd/vendor/github.com/google/pprof/profile/merge.go
index e00829cc34..a5440b521e 100644
--- a/src/cmd/vendor/github.com/google/pprof/profile/merge.go
+++ b/src/cmd/vendor/github.com/google/pprof/profile/merge.go
@@ -64,7 +64,7 @@ func Merge(srcs []*Profile) (*Profile, error) {
// represents the main binary. Take the first Mapping we see,
// otherwise the operations below will add mappings in an
// arbitrary order.
- pm.mapMapping(srcs[0].Mapping[0])
+ pm.mapMapping(src.Mapping[0])
}
for _, s := range src.Sample {
@@ -234,10 +234,11 @@ func (pm *profileMerger) mapLocation(src *Location) *Location {
mi := pm.mapMapping(src.Mapping)
l := &Location{
- ID: uint64(len(pm.p.Location) + 1),
- Mapping: mi.m,
- Address: uint64(int64(src.Address) + mi.offset),
- Line: make([]Line, len(src.Line)),
+ ID: uint64(len(pm.p.Location) + 1),
+ Mapping: mi.m,
+ Address: uint64(int64(src.Address) + mi.offset),
+ Line: make([]Line, len(src.Line)),
+ IsFolded: src.IsFolded,
}
for i, ln := range src.Line {
l.Line[i] = pm.mapLine(ln)
@@ -258,7 +259,8 @@ func (pm *profileMerger) mapLocation(src *Location) *Location {
// key generates locationKey to be used as a key for maps.
func (l *Location) key() locationKey {
key := locationKey{
- addr: l.Address,
+ addr: l.Address,
+ isFolded: l.IsFolded,
}
if l.Mapping != nil {
// Normalizes address to handle address space randomization.
@@ -279,6 +281,7 @@ func (l *Location) key() locationKey {
type locationKey struct {
addr, mappingID uint64
lines string
+ isFolded bool
}
func (pm *profileMerger) mapMapping(src *Mapping) mapInfo {
@@ -422,6 +425,7 @@ func combineHeaders(srcs []*Profile) (*Profile, error) {
var timeNanos, durationNanos, period int64
var comments []string
+ seenComments := map[string]bool{}
var defaultSampleType string
for _, s := range srcs {
if timeNanos == 0 || s.TimeNanos < timeNanos {
@@ -431,7 +435,12 @@ func combineHeaders(srcs []*Profile) (*Profile, error) {
if period == 0 || period < s.Period {
period = s.Period
}
- comments = append(comments, s.Comments...)
+ for _, c := range s.Comments {
+ if seen := seenComments[c]; !seen {
+ comments = append(comments, c)
+ seenComments[c] = true
+ }
+ }
if defaultSampleType == "" {
defaultSampleType = s.DefaultSampleType
}
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/profile.go b/src/cmd/vendor/github.com/google/pprof/profile/profile.go
index a0f53efe3e..350538bf43 100644
--- a/src/cmd/vendor/github.com/google/pprof/profile/profile.go
+++ b/src/cmd/vendor/github.com/google/pprof/profile/profile.go
@@ -109,10 +109,11 @@ type Mapping struct {
// Location corresponds to Profile.Location
type Location struct {
- ID uint64
- Mapping *Mapping
- Address uint64
- Line []Line
+ ID uint64
+ Mapping *Mapping
+ Address uint64
+ Line []Line
+ IsFolded bool
mappingIDX uint64
}
@@ -163,7 +164,7 @@ func ParseData(data []byte) (*Profile, error) {
return nil, fmt.Errorf("decompressing profile: %v", err)
}
}
- if p, err = ParseUncompressed(data); err != nil && err != errNoData {
+ if p, err = ParseUncompressed(data); err != nil && err != errNoData && err != errConcatProfile {
p, err = parseLegacy(data)
}
@@ -180,6 +181,7 @@ func ParseData(data []byte) (*Profile, error) {
var errUnrecognized = fmt.Errorf("unrecognized profile format")
var errMalformed = fmt.Errorf("malformed profile format")
var errNoData = fmt.Errorf("empty input file")
+var errConcatProfile = fmt.Errorf("concatenated profiles detected")
func parseLegacy(data []byte) (*Profile, error) {
parsers := []func([]byte) (*Profile, error){
@@ -591,6 +593,9 @@ func (l *Location) string() string {
if m := l.Mapping; m != nil {
locStr = locStr + fmt.Sprintf("M=%d ", m.ID)
}
+ if l.IsFolded {
+ locStr = locStr + "[F] "
+ }
if len(l.Line) == 0 {
ss = append(ss, locStr)
}
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/profile_test.go b/src/cmd/vendor/github.com/google/pprof/profile/profile_test.go
index bc2ab8bdd1..ab020275cb 100644
--- a/src/cmd/vendor/github.com/google/pprof/profile/profile_test.go
+++ b/src/cmd/vendor/github.com/google/pprof/profile/profile_test.go
@@ -73,11 +73,11 @@ func TestParse(t *testing.T) {
}
// Reencode and decode.
- bw := bytes.NewBuffer(nil)
- if err := p.Write(bw); err != nil {
+ var bw bytes.Buffer
+ if err := p.Write(&bw); err != nil {
t.Fatalf("%s: %v", source, err)
}
- if p, err = Parse(bw); err != nil {
+ if p, err = Parse(&bw); err != nil {
t.Fatalf("%s: %v", source, err)
}
js2 := p.String()
@@ -108,6 +108,21 @@ func TestParseError(t *testing.T) {
}
}
+func TestParseConcatentated(t *testing.T) {
+ prof := testProfile1.Copy()
+ // Write the profile twice to buffer to create concatented profile.
+ var buf bytes.Buffer
+ prof.Write(&buf)
+ prof.Write(&buf)
+ _, err := Parse(&buf)
+ if err == nil {
+ t.Fatalf("got nil, want error")
+ }
+ if got, want := err.Error(), "parsing profile: concatenated profiles detected"; want != got {
+ t.Fatalf("got error %q, want error %q", got, want)
+ }
+}
+
func TestCheckValid(t *testing.T) {
const path = "testdata/java.cpu"
@@ -276,6 +291,7 @@ var cpuL = []*Location{
}
var testProfile1 = &Profile{
+ TimeNanos: 10000,
PeriodType: &ValueType{Type: "cpu", Unit: "milliseconds"},
Period: 1,
DurationNanos: 10e9,
@@ -330,6 +346,60 @@ var testProfile1 = &Profile{
Mapping: cpuM,
}
+var testProfile1NoMapping = &Profile{
+ PeriodType: &ValueType{Type: "cpu", Unit: "milliseconds"},
+ Period: 1,
+ DurationNanos: 10e9,
+ SampleType: []*ValueType{
+ {Type: "samples", Unit: "count"},
+ {Type: "cpu", Unit: "milliseconds"},
+ },
+ Sample: []*Sample{
+ {
+ Location: []*Location{cpuL[0]},
+ Value: []int64{1000, 1000},
+ Label: map[string][]string{
+ "key1": {"tag1"},
+ "key2": {"tag1"},
+ },
+ },
+ {
+ Location: []*Location{cpuL[1], cpuL[0]},
+ Value: []int64{100, 100},
+ Label: map[string][]string{
+ "key1": {"tag2"},
+ "key3": {"tag2"},
+ },
+ },
+ {
+ Location: []*Location{cpuL[2], cpuL[0]},
+ Value: []int64{10, 10},
+ Label: map[string][]string{
+ "key1": {"tag3"},
+ "key2": {"tag2"},
+ },
+ },
+ {
+ Location: []*Location{cpuL[3], cpuL[0]},
+ Value: []int64{10000, 10000},
+ Label: map[string][]string{
+ "key1": {"tag4"},
+ "key2": {"tag1"},
+ },
+ },
+ {
+ Location: []*Location{cpuL[4], cpuL[0]},
+ Value: []int64{1, 1},
+ Label: map[string][]string{
+ "key1": {"tag4"},
+ "key2": {"tag1"},
+ },
+ },
+ },
+ Location: cpuL,
+ Function: cpuF,
+}
+
var testProfile2 = &Profile{
PeriodType: &ValueType{Type: "cpu", Unit: "milliseconds"},
Period: 1,
@@ -577,6 +647,7 @@ func TestMerge(t *testing.T) {
// location should add up to 0).
prof := testProfile1.Copy()
+ prof.Comments = []string{"comment1"}
p1, err := Merge([]*Profile{prof, prof})
if err != nil {
t.Errorf("merge error: %v", err)
@@ -586,6 +657,9 @@ func TestMerge(t *testing.T) {
if err != nil {
t.Errorf("merge error: %v", err)
}
+ if got, want := len(prof.Comments), 1; got != want {
+ t.Errorf("len(prof.Comments) = %d, want %d", got, want)
+ }
// Use aggregation to merge locations at function granularity.
if err := prof.Aggregate(false, true, false, false, false); err != nil {
@@ -627,6 +701,39 @@ func TestMergeAll(t *testing.T) {
}
}
+func TestIsFoldedMerge(t *testing.T) {
+ testProfile1Folded := testProfile1.Copy()
+ testProfile1Folded.Location[0].IsFolded = true
+ testProfile1Folded.Location[1].IsFolded = true
+
+ for _, tc := range []struct {
+ name string
+ profs []*Profile
+ wantLocationLen int
+ }{
+ {
+ name: "folded and non-folded locations not merged",
+ profs: []*Profile{testProfile1.Copy(), testProfile1Folded.Copy()},
+ wantLocationLen: 7,
+ },
+ {
+ name: "identical folded locations are merged",
+ profs: []*Profile{testProfile1Folded.Copy(), testProfile1Folded.Copy()},
+ wantLocationLen: 5,
+ },
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ prof, err := Merge(tc.profs)
+ if err != nil {
+ t.Fatalf("merge error: %v", err)
+ }
+ if got, want := len(prof.Location), tc.wantLocationLen; got != want {
+ t.Fatalf("got %d locations, want %d locations", got, want)
+ }
+ })
+ }
+}
+
func TestNumLabelMerge(t *testing.T) {
for _, tc := range []struct {
name string
@@ -684,6 +791,40 @@ func TestNumLabelMerge(t *testing.T) {
}
}
+func TestEmptyMappingMerge(t *testing.T) {
+ // Aggregate a profile with itself and once again with a factor of
+ // -2. Should end up with an empty profile (all samples for a
+ // location should add up to 0).
+
+ prof1 := testProfile1.Copy()
+ prof2 := testProfile1NoMapping.Copy()
+ p1, err := Merge([]*Profile{prof2, prof1})
+ if err != nil {
+ t.Errorf("merge error: %v", err)
+ }
+ prof2.Scale(-2)
+ prof, err := Merge([]*Profile{p1, prof2})
+ if err != nil {
+ t.Errorf("merge error: %v", err)
+ }
+
+ // Use aggregation to merge locations at function granularity.
+ if err := prof.Aggregate(false, true, false, false, false); err != nil {
+ t.Errorf("aggregating after merge: %v", err)
+ }
+
+ samples := make(map[string]int64)
+ for _, s := range prof.Sample {
+ tb := locationHash(s)
+ samples[tb] = samples[tb] + s.Value[0]
+ }
+ for s, v := range samples {
+ if v != 0 {
+ t.Errorf("nonzero value for sample %s: %d", s, v)
+ }
+ }
+}
+
func TestNormalizeBySameProfile(t *testing.T) {
pb := testProfile1.Copy()
p := testProfile1.Copy()
diff --git a/src/cmd/vendor/github.com/google/pprof/profile/proto_test.go b/src/cmd/vendor/github.com/google/pprof/profile/proto_test.go
index e0832294ac..38b58c586d 100644
--- a/src/cmd/vendor/github.com/google/pprof/profile/proto_test.go
+++ b/src/cmd/vendor/github.com/google/pprof/profile/proto_test.go
@@ -52,6 +52,8 @@ var testF = []*Function{
{ID: 1, Name: "func1", SystemName: "func1", Filename: "file1"},
{ID: 2, Name: "func2", SystemName: "func2", Filename: "file1"},
{ID: 3, Name: "func3", SystemName: "func3", Filename: "file2"},
+ {ID: 4, Name: "func4", SystemName: "func4", Filename: "file3"},
+ {ID: 5, Name: "func5", SystemName: "func5", Filename: "file4"},
}
var testL = []*Location{
@@ -86,6 +88,22 @@ var testL = []*Location{
Mapping: testM[1],
Address: 12,
},
+ {
+ ID: 4,
+ Mapping: testM[1],
+ Address: 12,
+ Line: []Line{
+ {
+ Function: testF[4],
+ Line: 6,
+ },
+ {
+ Function: testF[4],
+ Line: 6,
+ },
+ },
+ IsFolded: true,
+ },
}
var all = &Profile{
@@ -133,9 +151,9 @@ var all = &Profile{
func TestMarshalUnmarshal(t *testing.T) {
// Write the profile, parse it, and ensure they're equal.
- buf := bytes.NewBuffer(nil)
- all.Write(buf)
- all2, err := Parse(buf)
+ var buf bytes.Buffer
+ all.Write(&buf)
+ all2, err := Parse(&buf)
if err != nil {
t.Fatal(err)
}