11package cmd
22
33import (
4- "fmt"
54 "github.com/google/pprof/profile"
65 "log"
6+ "regexp"
77 "sort"
88 "strings"
99)
1010
1111type 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
1718type 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.
2456func 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
6997func 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
0 commit comments