Skip to content

Commit

Permalink
In the tags command, print percentages relative to profile total. (#929)
Browse files Browse the repository at this point in the history
Before this change percentages were relative to the tag total and this
sometimes causes confusion for users as it makes it look like the tag is
set for all samples when it's not.

Note that the percentage calculation as implemented does not attempt to
be friendly to samples where a given tag has multiple values. Multiple
values per tag per sample are discouraged and we should deprecate them.
Maybe we should make pprof print a warning for such profiles.
  • Loading branch information
aalexand authored Feb 8, 2025
1 parent fc31438 commit a522070
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 43 deletions.
1 change: 1 addition & 0 deletions internal/driver/driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ func TestParse(t *testing.T) {
{"weblist=line(1000|3000)$,addresses,flat", "cpu"},
{"tags,tagfocus=400kb:", "heap_request"},
{"tags,tagfocus=+400kb:", "heap_request"},
{"tags,relative_percentages,tagfocus=400kb:", "heap_request"},
{"dot", "long_name_funcs"},
{"text", "long_name_funcs"},
}
Expand Down
20 changes: 10 additions & 10 deletions internal/driver/testdata/pprof.cpu.tags
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
key1: Total 1.1s
1.0s (89.29%): tag1
100.0ms ( 8.93%): tag2
10.0ms ( 0.89%): tag3
10.0ms ( 0.89%): tag4
key1: Total 1.12s of 1.12s ( 100%)
1s (89.29%): tag1
100ms ( 8.93%): tag2
10ms ( 0.89%): tag3
10ms ( 0.89%): tag4

key2: Total 1.0s
1.0s (99.02%): tag1
10.0ms ( 0.98%): tag2
key2: Total 1.02s of 1.12s (91.07%)
1.01s (90.18%): tag1
10ms ( 0.89%): tag2

key3: Total 100.0ms
100.0ms ( 100%): tag2
key3: Total 100ms of 1.12s ( 8.93%)
100ms ( 8.93%): tag2

8 changes: 4 additions & 4 deletions internal/driver/testdata/pprof.cpu.tags.focus.ignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
key1: Total 100.0ms
100.0ms ( 100%): tag2
key1: Total 100ms of 1.12s ( 8.93%)
100ms ( 8.93%): tag2

key3: Total 100.0ms
100.0ms ( 100%): tag2
key3: Total 100ms of 1.12s ( 8.93%)
100ms ( 8.93%): tag2

10 changes: 5 additions & 5 deletions internal/driver/testdata/pprof.heap.tags
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
bytes: Total 98.6MB
62.5MB (63.37%): 1.56MB
31.2MB (31.68%): 400kB
3.9MB ( 3.96%): 200kB
1000.0kB ( 0.99%): 100kB
bytes: Total 98.63MB of 98.63MB ( 100%)
62.50MB (63.37%): 1.56MB
31.25MB (31.68%): 400kB
3.91MB ( 3.96%): 200kB
1000kB ( 0.99%): 100kB

10 changes: 5 additions & 5 deletions internal/driver/testdata/pprof.heap.tags.unit
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
bytes: Total 103424000.0B
65536000.0B (63.37%): 1638400B
32768000.0B (31.68%): 409600B
4096000.0B ( 3.96%): 204800B
1024000.0B ( 0.99%): 102400B
bytes: Total 103424000B of 103424000B ( 100%)
65536000B (63.37%): 1638400B
32768000B (31.68%): 409600B
4096000B ( 3.96%): 204800B
1024000B ( 0.99%): 102400B

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
bytes: Total 93.75MB of 93.75MB ( 100%)
62.50MB (66.67%): 1.56MB
31.25MB (33.33%): 400kB

request: Total 93.75MB of 93.75MB ( 100%)
62.50MB (66.67%): 1.56MB
31.25MB (33.33%): 400kB

12 changes: 6 additions & 6 deletions internal/driver/testdata/pprof.heap_request.tags.focus
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
bytes: Total 93.8MB
62.5MB (66.67%): 1.56MB
31.2MB (33.33%): 400kB
bytes: Total 93.75MB of 98.63MB (95.05%)
62.50MB (63.37%): 1.56MB
31.25MB (31.68%): 400kB

request: Total 93.8MB
62.5MB (66.67%): 1.56MB
31.2MB (33.33%): 400kB
request: Total 93.75MB of 98.63MB (95.05%)
62.50MB (63.37%): 1.56MB
31.25MB (31.68%): 400kB

33 changes: 20 additions & 13 deletions internal/report/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -699,21 +699,26 @@ func printTags(w io.Writer, rpt *Report) error {
p := rpt.prof

o := rpt.options
formatTag := func(v int64, key string) string {
return measurement.ScaledLabel(v, key, o.OutputUnit)
formatTag := func(v int64, unit string) string {
return measurement.ScaledLabel(v, unit, o.OutputUnit)
}

// Hashtable to keep accumulate tags as key,value,count.
// Accumulate tags as key,value,count.
tagMap := make(map[string]map[string]int64)
// Note that we assume single value per tag per sample. Multiple values are
// encodable in the format but are discouraged.
tagTotalMap := make(map[string]int64)
for _, s := range p.Sample {
sampleValue := o.SampleValue(s.Value)
for key, vals := range s.Label {
for _, val := range vals {
valueMap, ok := tagMap[key]
if !ok {
valueMap = make(map[string]int64)
tagMap[key] = valueMap
}
valueMap[val] += o.SampleValue(s.Value)
valueMap[val] += sampleValue
tagTotalMap[key] += sampleValue
}
}
for key, vals := range s.NumLabel {
Expand All @@ -725,7 +730,8 @@ func printTags(w io.Writer, rpt *Report) error {
valueMap = make(map[string]int64)
tagMap[key] = valueMap
}
valueMap[val] += o.SampleValue(s.Value)
valueMap[val] += sampleValue
tagTotalMap[key] += sampleValue
}
}
}
Expand All @@ -736,22 +742,23 @@ func printTags(w io.Writer, rpt *Report) error {
}
tabw := tabwriter.NewWriter(w, 0, 0, 1, ' ', tabwriter.AlignRight)
for _, tagKey := range graph.SortTags(tagKeys, true) {
var total int64
key := tagKey.Name
tags := make([]*graph.Tag, 0, len(tagMap[key]))
for t, c := range tagMap[key] {
total += c
tags = append(tags, &graph.Tag{Name: t, Flat: c})
}

f, u := measurement.Scale(total, o.SampleUnit, o.OutputUnit)
fmt.Fprintf(tabw, "%s:\t Total %.1f%s\n", key, f, u)
tagTotal, profileTotal := tagTotalMap[key], rpt.Total()
if profileTotal > 0 {
fmt.Fprintf(tabw, "%s:\t Total %s of %s (%s)\n", key, rpt.formatValue(tagTotal), rpt.formatValue(profileTotal), measurement.Percentage(tagTotal, profileTotal))
} else {
fmt.Fprintf(tabw, "%s:\t Total %s of %s\n", key, rpt.formatValue(tagTotal), rpt.formatValue(profileTotal))
}
for _, t := range graph.SortTags(tags, true) {
f, u := measurement.Scale(t.FlatValue(), o.SampleUnit, o.OutputUnit)
if total > 0 {
fmt.Fprintf(tabw, " \t%.1f%s (%s):\t %s\n", f, u, measurement.Percentage(t.FlatValue(), total), t.Name)
if profileTotal > 0 {
fmt.Fprintf(tabw, " \t%s (%s):\t %s\n", rpt.formatValue(t.FlatValue()), measurement.Percentage(t.FlatValue(), profileTotal), t.Name)
} else {
fmt.Fprintf(tabw, " \t%.1f%s:\t %s\n", f, u, t.Name)
fmt.Fprintf(tabw, " \t%s:\t %s\n", rpt.formatValue(t.FlatValue()), t.Name)
}
}
fmt.Fprintln(tabw)
Expand Down

0 comments on commit a522070

Please sign in to comment.