|
@@ -204,11 +204,18 @@ func SortTags(t []*Tag, flat bool) []*Tag {
|
204
|
204
|
}
|
205
|
205
|
|
206
|
206
|
// New summarizes performance data from a profile into a graph.
|
207
|
|
-func New(prof *profile.Profile, o *Options) (g *Graph) {
|
|
207
|
+func New(prof *profile.Profile, o *Options) *Graph {
|
208
|
208
|
if o.CallTree {
|
209
|
209
|
return newTree(prof, o)
|
210
|
210
|
}
|
|
211
|
+ g, _ := newGraph(prof, o)
|
|
212
|
+ return g
|
|
213
|
+}
|
211
|
214
|
|
|
215
|
+// newGraph computes a graph from a profile. It returns the graph, and
|
|
216
|
+// a map from the profile location indices to the corresponding graph
|
|
217
|
+// nodes.
|
|
218
|
+func newGraph(prof *profile.Profile, o *Options) (*Graph, map[uint64]Nodes) {
|
212
|
219
|
nodes, locationMap := CreateNodes(prof, o.ObjNames, o.KeptNodes)
|
213
|
220
|
for _, sample := range prof.Sample {
|
214
|
221
|
weight := o.SampleValue(sample.Value)
|
|
@@ -252,7 +259,7 @@ func New(prof *profile.Profile, o *Options) (g *Graph) {
|
252
|
259
|
}
|
253
|
260
|
}
|
254
|
261
|
|
255
|
|
- return selectNodesForGraph(nodes, o.DropNegative)
|
|
262
|
+ return selectNodesForGraph(nodes, o.DropNegative), locationMap
|
256
|
263
|
}
|
257
|
264
|
|
258
|
265
|
func selectNodesForGraph(nodes Nodes, dropNegative bool) *Graph {
|
|
@@ -340,6 +347,31 @@ func joinLabels(s *profile.Sample) string {
|
340
|
347
|
return strings.Join(labels, `\n`)
|
341
|
348
|
}
|
342
|
349
|
|
|
350
|
+// TrimProfile reduces the size of a profile by removing information
|
|
351
|
+// about locations that contribute to infrequent graph nodes,
|
|
352
|
+// determined by the value of nodefraction. The locations are
|
|
353
|
+// preserved, but their line information is removed.
|
|
354
|
+func TrimProfile(p *profile.Profile, o *Options, nodeFraction float64) *profile.Profile {
|
|
355
|
+ g, locationMap := newGraph(p, o)
|
|
356
|
+
|
|
357
|
+ totalValue, _ := g.Nodes.Sum()
|
|
358
|
+ cutoff := abs64(int64(float64(totalValue) * nodeFraction))
|
|
359
|
+
|
|
360
|
+ for _, l := range p.Location {
|
|
361
|
+ nodes := locationMap[l.ID]
|
|
362
|
+ if len(nodes) == 0 || len(l.Line) != len(nodes) {
|
|
363
|
+ continue
|
|
364
|
+ }
|
|
365
|
+ for i, n := range nodes {
|
|
366
|
+ if n.Cum < cutoff {
|
|
367
|
+ l.Line[i] = profile.Line{}
|
|
368
|
+ }
|
|
369
|
+ }
|
|
370
|
+ }
|
|
371
|
+
|
|
372
|
+ return p.Compact()
|
|
373
|
+}
|
|
374
|
+
|
343
|
375
|
// isNegative returns true if the node is considered as "negative" for the
|
344
|
376
|
// purposes of drop_negative.
|
345
|
377
|
func isNegative(n *Node) bool {
|
|
@@ -391,29 +423,41 @@ func (nm NodeMap) findOrInsertLocation(l *profile.Location, keepBinary bool, kep
|
391
|
423
|
}
|
392
|
424
|
return Nodes{nm.FindOrInsertNode(ni, kept)}
|
393
|
425
|
}
|
394
|
|
- var locNodes Nodes
|
395
|
|
- for _, line := range l.Line {
|
396
|
|
- ni := NodeInfo{
|
397
|
|
- Address: l.Address,
|
398
|
|
- Lineno: int(line.Line),
|
|
426
|
+ locNodes := make(Nodes, len(l.Line))
|
|
427
|
+ for li := range l.Line {
|
|
428
|
+ if ni := nodeInfo(l, li, objfile, keepBinary); ni != nil {
|
|
429
|
+ locNodes[li] = nm.FindOrInsertNode(*ni, kept)
|
399
|
430
|
}
|
|
431
|
+ }
|
|
432
|
+ return locNodes
|
|
433
|
+}
|
400
|
434
|
|
401
|
|
- if line.Function != nil {
|
402
|
|
- ni.Name = line.Function.Name
|
403
|
|
- ni.OrigName = line.Function.SystemName
|
404
|
|
- if fname := line.Function.Filename; fname != "" {
|
405
|
|
- ni.File = filepath.Clean(fname)
|
406
|
|
- }
|
407
|
|
- if keepBinary {
|
408
|
|
- ni.StartLine = int(line.Function.StartLine)
|
409
|
|
- }
|
410
|
|
- }
|
411
|
|
- if keepBinary || line.Function == nil {
|
412
|
|
- ni.Objfile = objfile
|
|
435
|
+func nodeInfo(l *profile.Location, li int, objfile string, keepBinary bool) *NodeInfo {
|
|
436
|
+ if !keepBinary {
|
|
437
|
+ objfile = ""
|
|
438
|
+ }
|
|
439
|
+ line := l.Line[li]
|
|
440
|
+ if line.Function == nil {
|
|
441
|
+ if l.Address == 0 {
|
|
442
|
+ return nil
|
413
|
443
|
}
|
414
|
|
- locNodes = append(locNodes, nm.FindOrInsertNode(ni, kept))
|
|
444
|
+ return &NodeInfo{Address: l.Address, Objfile: objfile}
|
415
|
445
|
}
|
416
|
|
- return locNodes
|
|
446
|
+
|
|
447
|
+ ni := &NodeInfo{
|
|
448
|
+ Address: l.Address,
|
|
449
|
+ Lineno: int(line.Line),
|
|
450
|
+ Name: line.Function.Name,
|
|
451
|
+ OrigName: line.Function.SystemName,
|
|
452
|
+ Objfile: objfile,
|
|
453
|
+ }
|
|
454
|
+ if fname := line.Function.Filename; fname != "" {
|
|
455
|
+ ni.File = filepath.Clean(fname)
|
|
456
|
+ }
|
|
457
|
+ if keepBinary {
|
|
458
|
+ ni.StartLine = int(line.Function.StartLine)
|
|
459
|
+ }
|
|
460
|
+ return ni
|
417
|
461
|
}
|
418
|
462
|
|
419
|
463
|
type tags struct {
|