|
@@ -203,7 +203,7 @@ func (rpt *Report) newGraph(nodes graph.NodeSet) *graph.Graph {
|
203
|
203
|
gopt := &graph.Options{
|
204
|
204
|
SampleValue: o.SampleValue,
|
205
|
205
|
FormatTag: formatTag,
|
206
|
|
- CallTree: o.CallTree && o.OutputFormat == Dot,
|
|
206
|
+ CallTree: o.CallTree && (o.OutputFormat == Dot || o.OutputFormat == Callgrind),
|
207
|
207
|
DropNegative: o.DropNegative,
|
208
|
208
|
KeptNodes: nodes,
|
209
|
209
|
}
|
|
@@ -627,13 +627,14 @@ func printCallgrind(w io.Writer, rpt *Report) error {
|
627
|
627
|
g, _, _, _ := rpt.newTrimmedGraph()
|
628
|
628
|
rpt.selectOutputUnit(g)
|
629
|
629
|
|
|
630
|
+ nodeNames := getDisambiguatedNames(g)
|
630
|
631
|
fmt.Fprintln(w, "events:", o.SampleType+"("+o.OutputUnit+")")
|
631
|
632
|
|
632
|
633
|
files := make(map[string]int)
|
633
|
634
|
names := make(map[string]int)
|
634
|
635
|
for _, n := range g.Nodes {
|
635
|
636
|
fmt.Fprintln(w, "fl="+callgrindName(files, n.Info.File))
|
636
|
|
- fmt.Fprintln(w, "fn="+callgrindName(names, n.Info.Name))
|
|
637
|
+ fmt.Fprintln(w, "fn="+callgrindName(names, nodeNames[n]))
|
637
|
638
|
sv, _ := measurement.Scale(n.Flat, o.SampleUnit, o.OutputUnit)
|
638
|
639
|
fmt.Fprintf(w, "%d %d\n", n.Info.Lineno, int64(sv))
|
639
|
640
|
|
|
@@ -642,7 +643,7 @@ func printCallgrind(w io.Writer, rpt *Report) error {
|
642
|
643
|
c, _ := measurement.Scale(out.Weight, o.SampleUnit, o.OutputUnit)
|
643
|
644
|
callee := out.Dest
|
644
|
645
|
fmt.Fprintln(w, "cfl="+callgrindName(files, callee.Info.File))
|
645
|
|
- fmt.Fprintln(w, "cfn="+callgrindName(names, callee.Info.Name))
|
|
646
|
+ fmt.Fprintln(w, "cfn="+callgrindName(names, nodeNames[callee]))
|
646
|
647
|
// pprof doesn't have a flat weight for a call, leave as 0.
|
647
|
648
|
fmt.Fprintln(w, "calls=0", callee.Info.Lineno)
|
648
|
649
|
fmt.Fprintln(w, n.Info.Lineno, int64(c))
|
|
@@ -653,6 +654,48 @@ func printCallgrind(w io.Writer, rpt *Report) error {
|
653
|
654
|
return nil
|
654
|
655
|
}
|
655
|
656
|
|
|
657
|
+// getDisambiguatedNames returns a map from each node in the graph to
|
|
658
|
+// the name to use in the callgrind output. Callgrind merges all
|
|
659
|
+// functions with the same [file name, function name]. Add a [%d/n]
|
|
660
|
+// suffix to disambiguate nodes with different values of
|
|
661
|
+// node.Function, which we want to keep separate. In particular, this
|
|
662
|
+// affects graphs created with --call_tree, where nodes from different
|
|
663
|
+// contexts are associated to different Functions.
|
|
664
|
+func getDisambiguatedNames(g *graph.Graph) map[*graph.Node]string {
|
|
665
|
+ nodeName := make(map[*graph.Node]string, len(g.Nodes))
|
|
666
|
+
|
|
667
|
+ type names struct {
|
|
668
|
+ file, function string
|
|
669
|
+ }
|
|
670
|
+
|
|
671
|
+ // nameFunctionIndex maps the callgrind names (filename, function)
|
|
672
|
+ // to the node.Function values found for that name, and each
|
|
673
|
+ // node.Function value to a sequential index to be used on the
|
|
674
|
+ // disambiguated name.
|
|
675
|
+ nameFunctionIndex := make(map[names]map[*graph.Node]int)
|
|
676
|
+ for _, n := range g.Nodes {
|
|
677
|
+ nm := names{n.Info.File, n.Info.Name}
|
|
678
|
+ p, ok := nameFunctionIndex[nm]
|
|
679
|
+ if !ok {
|
|
680
|
+ p = make(map[*graph.Node]int)
|
|
681
|
+ nameFunctionIndex[nm] = p
|
|
682
|
+ }
|
|
683
|
+ if _, ok := p[n.Function]; !ok {
|
|
684
|
+ p[n.Function] = len(p)
|
|
685
|
+ }
|
|
686
|
+ }
|
|
687
|
+
|
|
688
|
+ for _, n := range g.Nodes {
|
|
689
|
+ nm := names{n.Info.File, n.Info.Name}
|
|
690
|
+ nodeName[n] = n.Info.Name
|
|
691
|
+ if p := nameFunctionIndex[nm]; len(p) > 1 {
|
|
692
|
+ // If there is more than one function, add suffix to disambiguate.
|
|
693
|
+ nodeName[n] += fmt.Sprintf(" [%d/%d]", p[n.Function]+1, len(p))
|
|
694
|
+ }
|
|
695
|
+ }
|
|
696
|
+ return nodeName
|
|
697
|
+}
|
|
698
|
+
|
656
|
699
|
// callgrindName implements the callgrind naming compression scheme.
|
657
|
700
|
// For names not previously seen returns "(N) name", where N is a
|
658
|
701
|
// unique index. For names previously seen returns "(N)" where N is
|