Преглед на файлове

Speed up graph.New

Non functional changes -- pre-size maps and slices to reduce
cost of building a graph out of a profile.
Raul Silvera преди 9 години
родител
ревизия
9f07e766be
променени са 1 файла, в които са добавени 28 реда и са изтрити 18 реда
  1. 28
    18
      internal/graph/graph.go

+ 28
- 18
internal/graph/graph.go Целия файл

@@ -20,6 +20,7 @@ import (
20 20
 	"math"
21 21
 	"path/filepath"
22 22
 	"sort"
23
+	"strconv"
23 24
 	"strings"
24 25
 
25 26
 	"github.com/google/pprof/profile"
@@ -156,8 +157,10 @@ type NodeSet map[NodeInfo]bool
156 157
 // If parent is non-nil, return a match with the same parent.
157 158
 // If kept is non-nil, nodes are only added if they can be located on it.
158 159
 func (m NodeMap) FindOrInsertNode(info NodeInfo, parent *Node, kept NodeSet) *Node {
159
-	if kept != nil && !kept[info] {
160
-		return nil
160
+	if kept != nil {
161
+		if _, ok := kept[info]; !ok {
162
+			return nil
163
+		}
161 164
 	}
162 165
 
163 166
 	extendedInfo := ExtendedNodeInfo{
@@ -165,7 +168,7 @@ func (m NodeMap) FindOrInsertNode(info NodeInfo, parent *Node, kept NodeSet) *No
165 168
 		parent,
166 169
 	}
167 170
 
168
-	if n := m[extendedInfo]; n != nil {
171
+	if n, ok := m[extendedInfo]; ok {
169 172
 		return n
170 173
 	}
171 174
 
@@ -216,8 +219,9 @@ func SortTags(t []*Tag, flat bool) []*Tag {
216 219
 
217 220
 // New summarizes performance data from a profile into a graph.
218 221
 func New(prof *profile.Profile, o *Options) (g *Graph) {
222
+	const averageNodesPerLocation = 2
219 223
 	locations := NewLocInfo(prof, o.ObjNames)
220
-	nm := make(NodeMap)
224
+	nm := make(NodeMap, len(prof.Location)*averageNodesPerLocation)
221 225
 	for _, sample := range prof.Sample {
222 226
 		if sample.Location == nil {
223 227
 			continue
@@ -227,8 +231,8 @@ func New(prof *profile.Profile, o *Options) (g *Graph) {
227 231
 		// Keep track of the index on the Sample for each frame,
228 232
 		// to determine inlining status.
229 233
 
230
-		var stack []NodeInfo
231
-		var locIndex []int
234
+		stack := make([]NodeInfo, 0, len(sample.Location))
235
+		locIndex := make([]int, 0, len(sample.Location)*averageNodesPerLocation)
232 236
 		for i, loc := range sample.Location {
233 237
 			id := loc.ID
234 238
 			stack = append(stack, locations[id]...)
@@ -238,7 +242,8 @@ func New(prof *profile.Profile, o *Options) (g *Graph) {
238 242
 		}
239 243
 
240 244
 		weight := o.SampleValue(sample.Value)
241
-		seenEdge := make(map[*Node]map[*Node]bool)
245
+		seenNode := make(map[*Node]bool, len(stack))
246
+		seenEdge := make(map[nodePair]bool, len(stack))
242 247
 		var nn *Node
243 248
 		nlocIndex := -1
244 249
 		residual := false
@@ -259,13 +264,13 @@ func New(prof *profile.Profile, o *Options) (g *Graph) {
259 264
 				n.addSample(sample, weight, o.FormatTag, true)
260 265
 			}
261 266
 			// Add cum weight to all nodes in stack, avoiding double counting.
262
-			if seenEdge[n] == nil {
263
-				seenEdge[n] = make(map[*Node]bool)
267
+			if _, ok := seenNode[n]; !ok {
268
+				seenNode[n] = true
264 269
 				n.addSample(sample, weight, o.FormatTag, false)
265 270
 			}
266 271
 			// Update edge weights for all edges in stack, avoiding double counting.
267
-			if nn != nil && n != nn && !seenEdge[n][nn] {
268
-				seenEdge[n][nn] = true
272
+			if _, ok := seenEdge[nodePair{n, nn}]; !ok && nn != nil && n != nn {
273
+				seenEdge[nodePair{n, nn}] = true
269 274
 				// This is an inlined edge if the caller and the callee
270 275
 				// correspond to the same entry in the sample.
271 276
 				nn.BumpWeight(n, weight, residual, locIndex[i-1] == nlocIndex)
@@ -288,6 +293,10 @@ func New(prof *profile.Profile, o *Options) (g *Graph) {
288 293
 	return &Graph{ns}
289 294
 }
290 295
 
296
+type nodePair struct {
297
+	src, dest *Node
298
+}
299
+
291 300
 // isNegative returns true if the node is considered as "negative" for the
292 301
 // purposes of drop_negative.
293 302
 func isNegative(n *Node) bool {
@@ -409,15 +418,12 @@ func (n *Node) addSample(s *profile.Sample, value int64, format func(int64, stri
409 418
 		n.NumericTags[joinedLabels] = numericTags
410 419
 	}
411 420
 	// Add numeric tags
421
+	if format == nil {
422
+		format = defaultLabelFormat
423
+	}
412 424
 	for key, nvals := range s.NumLabel {
413 425
 		for _, v := range nvals {
414
-			var label string
415
-			if format != nil {
416
-				label = format(v, key)
417
-			} else {
418
-				label = fmt.Sprintf("%d", v)
419
-			}
420
-			t := numericTags.findOrAddTag(label, key, v)
426
+			t := numericTags.findOrAddTag(format(v, key), key, v)
421 427
 			if flat {
422 428
 				t.Flat += value
423 429
 			} else {
@@ -427,6 +433,10 @@ func (n *Node) addSample(s *profile.Sample, value int64, format func(int64, stri
427 433
 	}
428 434
 }
429 435
 
436
+func defaultLabelFormat(v int64, key string) string {
437
+	return strconv.FormatInt(v, 10)
438
+}
439
+
430 440
 func (m TagMap) findOrAddTag(label, unit string, value int64) *Tag {
431 441
 	l := m[label]
432 442
 	if l == nil {