Просмотр исходного кода

Regresses NodeSet interface

This is to keep the new TrimTree functionality from breaking any code
currently using the public interface. We do this by separating NodeSet
from nodePtrSet and creating different functions for each.
Wade Simba Khadder 9 лет назад
Родитель
Сommit
7c0b6f60fd
4 измененных файлов: 69 добавлений и 35 удалений
  1. 46
    16
      internal/graph/graph.go
  2. 4
    6
      internal/graph/graph_test.go
  3. 17
    11
      internal/report/report.go
  4. 2
    2
      internal/report/source.go

+ 46
- 16
internal/graph/graph.go Просмотреть файл

@@ -143,17 +143,16 @@ func (i *NodeInfo) NameComponents() []string {
143 143
 type NodeMap map[NodeInfo]*Node
144 144
 
145 145
 // NodeSet maps is a collection of node info structs.
146
-type NodeSet struct {
147
-	Info map[NodeInfo]bool
148
-	Ptr  map[*Node]bool
149
-}
146
+type NodeSet map[NodeInfo]bool
147
+
148
+type nodePtrSet map[*Node]bool
150 149
 
151 150
 // FindOrInsertNode takes the info for a node and either returns a matching node
152 151
 // from the node map if one exists, or adds one to the map if one does not.
153 152
 // If kept is non-nil, nodes are only added if they can be located on it.
154 153
 func (nm NodeMap) FindOrInsertNode(info NodeInfo, kept NodeSet) *Node {
155
-	if kept.Info != nil {
156
-		if _, ok := kept.Info[info]; !ok {
154
+	if kept != nil {
155
+		if _, ok := kept[info]; !ok {
157 156
 			return nil
158 157
 		}
159 158
 	}
@@ -337,10 +336,10 @@ func newTree(prof *profile.Profile, o *Options) (g *Graph) {
337 336
 
338 337
 // Trims a Graph that is in forest form to contain only the nodes in kept. This
339 338
 // will not work correctly in the case that a node has multiple parents.
340
-func (g *Graph) TrimTree(kept NodeSet) {
339
+func (g *Graph) TrimTree(kept nodePtrSet) {
341 340
 	// Creates a new list of nodes
342 341
 	oldNodes := g.Nodes
343
-	g.Nodes = make(Nodes, 0, len(kept.Ptr))
342
+	g.Nodes = make(Nodes, 0, len(kept))
344 343
 
345 344
 	for _, cur := range oldNodes {
346 345
 		// A node may not have multiple parents
@@ -349,7 +348,7 @@ func (g *Graph) TrimTree(kept NodeSet) {
349 348
 		}
350 349
 
351 350
 		// If a node should be kept, add it to the next list of nodes
352
-		if _, ok := kept.Ptr[cur]; ok {
351
+		if _, ok := kept[cur]; ok {
353 352
 			g.Nodes = append(g.Nodes, cur)
354 353
 			continue
355 354
 		}
@@ -600,19 +599,36 @@ func (g *Graph) DiscardLowFrequencyNodes(nodeCutoff int64) NodeSet {
600 599
 	return makeNodeSet(g.Nodes, nodeCutoff)
601 600
 }
602 601
 
602
+// discardLowFrequencyNodePtrs returns a NodePtrSet of nodes at or over a
603
+// specific cum value cutoff.
604
+func (g *Graph) DiscardLowFrequencyNodePtrs(nodeCutoff int64) nodePtrSet {
605
+	cutNodes := getNodesWithCumCutoff(g.Nodes, nodeCutoff)
606
+	kept := make(nodePtrSet, len(cutNodes))
607
+	for _, n := range cutNodes {
608
+		kept[n] = true
609
+	}
610
+	return kept
611
+}
612
+
603 613
 func makeNodeSet(nodes Nodes, nodeCutoff int64) NodeSet {
604
-	kept := NodeSet{
605
-		Info: make(map[NodeInfo]bool, len(nodes)),
606
-		Ptr:  make(map[*Node]bool, len(nodes)),
614
+	cutNodes := getNodesWithCumCutoff(nodes, nodeCutoff)
615
+	kept := make(NodeSet, len(cutNodes))
616
+	for _, n := range cutNodes {
617
+		kept[n.Info] = true
607 618
 	}
619
+	return kept
620
+}
621
+
622
+// Returns all the nodes who have a Cum value greater than or equal to cutoff
623
+func getNodesWithCumCutoff(nodes Nodes, nodeCutoff int64) Nodes {
624
+	cutoffNodes := make(Nodes, 0, len(nodes))
608 625
 	for _, n := range nodes {
609 626
 		if abs64(n.Cum) < nodeCutoff {
610 627
 			continue
611 628
 		}
612
-		kept.Info[n.Info] = true
613
-		kept.Ptr[n] = true
629
+		cutoffNodes = append(cutoffNodes, n)
614 630
 	}
615
-	return kept
631
+	return cutoffNodes
616 632
 }
617 633
 
618 634
 // TrimLowFrequencyTags removes tags that have less than
@@ -667,8 +683,22 @@ func (g *Graph) SortNodes(cum bool, visualMode bool) {
667 683
 	}
668 684
 }
669 685
 
686
+// selectTopNodePtrs returns a set of the top maxNodes *Node in a graph.
687
+func (g *Graph) SelectTopNodePtrs(maxNodes int, visualMode bool) nodePtrSet {
688
+	set := make(nodePtrSet)
689
+	for _, node := range g.selectTopNodes(maxNodes, visualMode) {
690
+		set[node] = true
691
+	}
692
+	return set
693
+}
694
+
670 695
 // SelectTopNodes returns a set of the top maxNodes nodes in a graph.
671 696
 func (g *Graph) SelectTopNodes(maxNodes int, visualMode bool) NodeSet {
697
+	return makeNodeSet(g.selectTopNodes(maxNodes, visualMode), 0)
698
+}
699
+
700
+// selectTopNodes returns a slice of the top maxNodes nodes in a graph
701
+func (g *Graph) selectTopNodes(maxNodes int, visualMode bool) Nodes {
672 702
 	if maxNodes > 0 {
673 703
 		if visualMode {
674 704
 			var count int
@@ -685,7 +715,7 @@ func (g *Graph) SelectTopNodes(maxNodes int, visualMode bool) NodeSet {
685 715
 	if maxNodes > len(g.Nodes) {
686 716
 		maxNodes = len(g.Nodes)
687 717
 	}
688
-	return makeNodeSet(g.Nodes[:maxNodes], 0)
718
+	return g.Nodes[:maxNodes]
689 719
 }
690 720
 
691 721
 // countTags counts the tags with flat count. This underestimates the

+ 4
- 6
internal/graph/graph_test.go Просмотреть файл

@@ -109,7 +109,7 @@ type ExpectedNode struct {
109 109
 type TrimTreeTestCase struct {
110 110
 	Initial  *Graph
111 111
 	Expected []ExpectedNode
112
-	Keep     NodeSet
112
+	Keep nodePtrSet
113 113
 }
114 114
 
115 115
 // Makes the edge from parent to child residual
@@ -143,11 +143,9 @@ func createEmptyNode() *Node {
143 143
 }
144 144
 
145 145
 // Creates an array of ExpectedNodes from nodes.
146
-func createExpectedNodes(nodes ...*Node) ([]ExpectedNode, NodeSet) {
146
+func createExpectedNodes(nodes ...*Node) ([]ExpectedNode, nodePtrSet) {
147 147
 	Expected := make([]ExpectedNode, len(nodes))
148
-	Keep := NodeSet{
149
-		Ptr: make(map[*Node]bool, len(nodes)),
150
-	}
148
+	Keep := make(nodePtrSet, len(nodes))
151 149
 
152 150
 	for i, node := range nodes {
153 151
 		Expected[i] = ExpectedNode{
@@ -155,7 +153,7 @@ func createExpectedNodes(nodes ...*Node) ([]ExpectedNode, NodeSet) {
155 153
 			In:   make(EdgeMap),
156 154
 			Out:  make(EdgeMap),
157 155
 		}
158
-		Keep.Ptr[node] = true
156
+		Keep[node] = true
159 157
 	}
160 158
 
161 159
 	return Expected, Keep

+ 17
- 11
internal/report/report.go Просмотреть файл

@@ -79,18 +79,21 @@ func (rpt *Report) newTrimmedGraph() (g *graph.Graph, origCount, droppedNodes, d
79 79
 	cumSort := o.CumSort
80 80
 
81 81
 	// First step: Build complete graph to identify low frequency nodes, based on their cum weight.
82
-	g = rpt.newGraph(graph.NodeSet{nil, nil})
82
+	g = rpt.newGraph(nil)
83 83
 	totalValue, _ := g.Nodes.Sum()
84 84
 	nodeCutoff := abs64(int64(float64(totalValue) * o.NodeFraction))
85 85
 	edgeCutoff := abs64(int64(float64(totalValue) * o.EdgeFraction))
86 86
 
87 87
 	// Filter out nodes with cum value below nodeCutoff.
88 88
 	if nodeCutoff > 0 {
89
-		if nodesKept := g.DiscardLowFrequencyNodes(nodeCutoff); len(g.Nodes) != len(nodesKept.Ptr) {
90
-			droppedNodes = len(g.Nodes) - len(nodesKept.Ptr)
91
-			if o.CallTree {
89
+		if o.CallTree {
90
+			if nodesKept := g.DiscardLowFrequencyNodePtrs(nodeCutoff); len(g.Nodes) != len(nodesKept) {
91
+				droppedNodes = len(g.Nodes) - len(nodesKept)
92 92
 				g.TrimTree(nodesKept)
93
-			} else {
93
+			}
94
+		} else {
95
+			if nodesKept := g.DiscardLowFrequencyNodes(nodeCutoff); len(g.Nodes) != len(nodesKept) {
96
+				droppedNodes = len(g.Nodes) - len(nodesKept)
94 97
 				g = rpt.newGraph(nodesKept)
95 98
 			}
96 99
 		}
@@ -104,13 +107,16 @@ func (rpt *Report) newTrimmedGraph() (g *graph.Graph, origCount, droppedNodes, d
104 107
 		// Remove low frequency tags and edges as they affect selection.
105 108
 		g.TrimLowFrequencyTags(nodeCutoff)
106 109
 		g.TrimLowFrequencyEdges(edgeCutoff)
107
-		if nodesKept := g.SelectTopNodes(nodeCount, visualMode); len(nodesKept.Ptr) != len(g.Nodes) {
108
-			if o.CallTree {
110
+		if o.CallTree {
111
+			if nodesKept := g.SelectTopNodePtrs(nodeCount, visualMode); len(g.Nodes) != len(nodesKept) {
109 112
 				g.TrimTree(nodesKept)
110
-			} else {
113
+				g.SortNodes(cumSort, visualMode)
114
+			}
115
+		} else {
116
+			if nodesKept := g.SelectTopNodes(nodeCount, visualMode); len(g.Nodes) != len(nodesKept) {
111 117
 				g = rpt.newGraph(nodesKept)
118
+				g.SortNodes(cumSort, visualMode)
112 119
 			}
113
-			g.SortNodes(cumSort, visualMode)
114 120
 		}
115 121
 	}
116 122
 
@@ -270,7 +276,7 @@ func printAssembly(w io.Writer, rpt *Report, obj plugin.ObjTool) error {
270 276
 	o := rpt.options
271 277
 	prof := rpt.prof
272 278
 
273
-	g := rpt.newGraph(graph.NodeSet{nil, nil})
279
+	g := rpt.newGraph(nil)
274 280
 
275 281
 	// If the regexp source can be parsed as an address, also match
276 282
 	// functions that land on that address.
@@ -578,7 +584,7 @@ func printTraces(w io.Writer, rpt *Report) error {
578 584
 
579 585
 	const separator = "-----------+-------------------------------------------------------"
580 586
 
581
-	_, locations := graph.CreateNodes(prof, false, graph.NodeSet{nil, nil})
587
+	_, locations := graph.CreateNodes(prof, false, nil)
582 588
 	for _, sample := range prof.Sample {
583 589
 		var stack graph.Nodes
584 590
 		for _, loc := range sample.Location {

+ 2
- 2
internal/report/source.go Просмотреть файл

@@ -37,7 +37,7 @@ import (
37 37
 // eliminate potential nondeterminism.
38 38
 func printSource(w io.Writer, rpt *Report) error {
39 39
 	o := rpt.options
40
-	g := rpt.newGraph(graph.NodeSet{nil, nil})
40
+	g := rpt.newGraph(nil)
41 41
 
42 42
 	// Identify all the functions that match the regexp provided.
43 43
 	// Group nodes for each matching function.
@@ -117,7 +117,7 @@ func printSource(w io.Writer, rpt *Report) error {
117 117
 // functions with samples that match the regexp rpt.options.symbol.
118 118
 func printWebSource(w io.Writer, rpt *Report, obj plugin.ObjTool) error {
119 119
 	o := rpt.options
120
-	g := rpt.newGraph(graph.NodeSet{nil, nil})
120
+	g := rpt.newGraph(nil)
121 121
 
122 122
 	// If the regexp source can be parsed as an address, also match
123 123
 	// functions that land on that address.