Skip to content

Commit 2fa472a

Browse files
committed
[add] Added flamegraph support
1 parent 1970fec commit 2fa472a

File tree

5 files changed

+57
-30
lines changed

5 files changed

+57
-30
lines changed

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ build:
2525
$(GOCMD) build .
2626

2727
fmt:
28-
$(GOFMT) ./...
28+
$(GOFMT) ./*.go
29+
$(GOFMT) ./cmd/*.go
2930

3031
lint:
3132
$(GOGET) github.com/golangci/golangci-lint/cmd/golangci-lint

cmd/export.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ func exportLogic() func(cmd *cobra.Command, args []string) {
5454
if err == nil {
5555
var w io.Writer
5656
// open output file
57-
fmt.Println()
5857
localExportLogic(w, report)
5958
} else {
6059
log.Fatal(err)
@@ -64,7 +63,6 @@ func exportLogic() func(cmd *cobra.Command, args []string) {
6463
for _, granularity := range granularityOptions {
6564
err, report := generateTextReports(granularity, args[0])
6665
if err == nil {
67-
fmt.Println()
6866
remoteExportLogic(report, granularity)
6967
} else {
7068
log.Fatal(err)
@@ -75,9 +73,9 @@ func exportLogic() func(cmd *cobra.Command, args []string) {
7573
log.Fatalf("An Error Occured %v", err)
7674
}
7775
remoteFlameGraphExport(finalTree)
78-
log.Printf("Successfully published profile data. Check it at: %s/gh/%s/%s/commit/%s/bench/%s/cpu", codeperfUrl, gitOrg, gitRepo, gitCommit, bench)
76+
log.Printf("Successfully published profile data")
77+
log.Printf("Check it at: %s/gh/%s/%s/commit/%s/bench/%s/cpu", codeperfUrl, gitOrg, gitRepo, gitCommit, bench)
7978
}
80-
8179
}
8280
}
8381

cmd/flagset.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package cmd
22

33
import (
44
"bufio"
5-
"fmt"
5+
"log"
66
"os"
77
)
88

@@ -88,11 +88,11 @@ func (ui *UI) ReadLine(prompt string) (string, error) {
8888
}
8989

9090
func (ui *UI) Print(args ...interface{}) {
91-
fmt.Fprint(os.Stderr, args...)
91+
log.Print(args...)
9292
}
9393

9494
func (ui *UI) PrintErr(args ...interface{}) {
95-
fmt.Fprint(os.Stderr, args...)
95+
log.Print(args...)
9696
}
9797

9898
func (ui *UI) IsTerminal() bool {

cmd/folded.go

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,74 @@
11
package cmd
22

33
import (
4-
"fmt"
54
"github.com/google/pprof/profile"
65
"log"
6+
"regexp"
77
"sort"
88
"strings"
99
)
1010

1111
type treeNode struct {
1212
Name string `json:"n"`
13+
FullName string `json:"f"`
1314
Cum int64 `json:"v"`
1415
Children map[string]*treeNode `json:"c"`
1516
}
1617

1718
type treeNodeSlice struct {
1819
Name string `json:"n"`
20+
FullName string `json:"f"`
1921
Cum int64 `json:"v"`
2022
Children []treeNodeSlice `json:"c"`
2123
}
2224

25+
var (
26+
// Removes package name and method arguments for Java method names.
27+
// See tests for examples.
28+
javaRegExp = regexp.MustCompile(`^(?:[a-z]\w*\.)*([A-Z][\w\$]*\.(?:<init>|[a-z][\w\$]*(?:\$\d+)?))(?:(?:\()|$)`)
29+
// Removes package name and method arguments for Go function names.
30+
// See tests for examples.
31+
goRegExp = regexp.MustCompile(`^(?:[\w\-\.]+\/)+(.+)`)
32+
// Removes potential module versions in a package path.
33+
goVerRegExp = regexp.MustCompile(`^(.*?)/v(?:[2-9]|[1-9][0-9]+)([./].*)$`)
34+
// Strips C++ namespace prefix from a C++ function / method name.
35+
// NOTE: Make sure to keep the template parameters in the name. Normally,
36+
// template parameters are stripped from the C++ names but when
37+
// -symbolize=demangle=templates flag is used, they will not be.
38+
// See tests for examples.
39+
cppRegExp = regexp.MustCompile(`^(?:[_a-zA-Z]\w*::)+(_*[A-Z]\w*::~?[_a-zA-Z]\w*(?:<.*>)?)`)
40+
cppAnonymousPrefixRegExp = regexp.MustCompile(`^\(anonymous namespace\)::`)
41+
)
42+
43+
// ShortenFunctionName returns a shortened version of a function's name.
44+
func ShortenFunctionName(f string) string {
45+
f = cppAnonymousPrefixRegExp.ReplaceAllString(f, "")
46+
f = goVerRegExp.ReplaceAllString(f, `${1}${2}`)
47+
for _, re := range []*regexp.Regexp{goRegExp, javaRegExp, cppRegExp} {
48+
if matches := re.FindStringSubmatch(f); len(matches) >= 2 {
49+
return strings.Join(matches[1:], "")
50+
}
51+
}
52+
return f
53+
}
54+
2355
// Convert marshals the given protobuf profile into folded text format.
2456
func profileToFolded(protobuf *profile.Profile) treeNodeSlice {
25-
rootNode := treeNode{"root", 0, make(map[string]*treeNode, 0)}
57+
rootNode := treeNode{"root", "root", 0, make(map[string]*treeNode, 0)}
2658
if err := protobuf.Aggregate(true, true, false, false, false); err != nil {
2759
log.Fatal(err)
2860
}
2961
protobuf = protobuf.Compact()
3062
sort.Slice(protobuf.Sample, func(i, j int) bool {
3163
return protobuf.Sample[i].Value[0] > protobuf.Sample[j].Value[0]
3264
})
65+
3366
for _, sample := range protobuf.Sample {
67+
var cum int64 = 0
68+
for _, val := range sample.Value {
69+
cum = cum + val
70+
break
71+
}
3472
var frames []string
3573
var currentNode *treeNode
3674
var currentMap map[string]*treeNode = rootNode.Children
@@ -39,37 +77,27 @@ func profileToFolded(protobuf *profile.Profile) treeNodeSlice {
3977
loc := sample.Location[len(sample.Location)-i-1]
4078
for j := range loc.Line {
4179
line := loc.Line[len(loc.Line)-j-1]
42-
fname := line.Function.Name
43-
currentNode, ok = currentMap[fname]
80+
fname := ShortenFunctionName(line.Function.Name)
81+
shortName := fname[strings.LastIndex(fname, ".")+1:]
82+
currentNode, ok = currentMap[shortName]
4483
if !ok {
45-
currentNode = &treeNode{fname, 0, make(map[string]*treeNode, 0)}
46-
currentMap[fname] = currentNode
84+
currentNode = &treeNode{shortName, fname, 0, make(map[string]*treeNode, 0)}
85+
currentMap[shortName] = currentNode
4786
}
87+
currentNode.Cum += cum
4888
currentMap = currentNode.Children
49-
frames = append(frames, fname)
89+
frames = append(frames, shortName)
5090
}
5191
}
52-
53-
var values []string
54-
for _, val := range sample.Value {
55-
values = append(values, fmt.Sprintf("%d", val))
56-
currentNode.Cum = currentNode.Cum + val
57-
break
58-
}
59-
fmt.Printf(
60-
"%s %s\n",
61-
strings.Join(frames, ";"),
62-
strings.Join(values, " "),
63-
)
6492
}
65-
finalTree := treeNodeSlice{rootNode.Name, rootNode.Cum, collapse(rootNode.Children)}
93+
finalTree := treeNodeSlice{rootNode.Name, rootNode.FullName, rootNode.Cum, collapse(rootNode.Children)}
6694
return finalTree
6795
}
6896

6997
func collapse(children map[string]*treeNode) (tree []treeNodeSlice) {
7098
tree = make([]treeNodeSlice, 0)
7199
for _, k := range children {
72-
nS := treeNodeSlice{k.Name, k.Cum, collapse(k.Children)}
100+
nS := treeNodeSlice{k.Name, k.FullName, k.Cum, collapse(k.Children)}
73101
tree = append(tree, nS)
74102
}
75103
return

cmd/root.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func init() {
7878
repoStartPos := strings.LastIndex(remoteUsed, "/") + 1
7979
defaultGitRepo = remoteUsed[repoStartPos : len(remoteUsed)-4]
8080
defaultGitCommit = refHash
81-
fmt.Printf("Detected the following git vars org=%s repo=%s hash=%s", defaultGitOrg, defaultGitRepo, defaultGitCommit)
81+
log.Printf("Detected the following git vars org=%s repo=%s hash=%s\n", defaultGitOrg, defaultGitRepo, defaultGitCommit)
8282
}
8383

8484
// Here you will define your flags and configuration settings.

0 commit comments

Comments
 (0)