Bläddra i källkod

Force saving the module name for unsymbolized frames (#394)

Force saving the module name for unsymbolized frames

In some cases pprof isn't saving the module name in graph nodes, so
reports end up with nodes of the form '<unknown>'.

The module name is often stripped to allow symbolized frames from
different versions of a binary to be merge.

Force saving the objfile name if the name is unknown so we can print
some information for unsymbolized frames.
Raul Silvera 6 år sedan
förälder
incheckning
4b87942090
2 ändrade filer med 91 tillägg och 7 borttagningar
  1. 5
    7
      internal/graph/graph.go
  2. 86
    0
      internal/graph/graph_test.go

+ 5
- 7
internal/graph/graph.go Visa fil

@@ -512,9 +512,7 @@ func isNegative(n *Node) bool {
512 512
 
513 513
 // CreateNodes creates graph nodes for all locations in a profile. It
514 514
 // returns set of all nodes, plus a mapping of each location to the
515
-// set of corresponding nodes (one per location.Line). If kept is
516
-// non-nil, only nodes in that set are included; nodes that do not
517
-// match are represented as a nil.
515
+// set of corresponding nodes (one per location.Line).
518 516
 func CreateNodes(prof *profile.Profile, o *Options) (Nodes, map[uint64]Nodes) {
519 517
 	locations := make(map[uint64]Nodes, len(prof.Location))
520 518
 	nm := make(NodeMap, len(prof.Location))
@@ -564,13 +562,13 @@ func nodeInfo(l *profile.Location, line profile.Line, objfile string, o *Options
564 562
 	if fname := line.Function.Filename; fname != "" {
565 563
 		ni.File = filepath.Clean(fname)
566 564
 	}
567
-	if o.ObjNames {
568
-		ni.Objfile = objfile
569
-		ni.StartLine = int(line.Function.StartLine)
570
-	}
571 565
 	if o.OrigFnNames {
572 566
 		ni.OrigName = line.Function.SystemName
573 567
 	}
568
+	if o.ObjNames || (ni.Name == "" && ni.OrigName == "") {
569
+		ni.Objfile = objfile
570
+		ni.StartLine = int(line.Function.StartLine)
571
+	}
574 572
 	return ni
575 573
 }
576 574
 

+ 86
- 0
internal/graph/graph_test.go Visa fil

@@ -3,6 +3,8 @@ package graph
3 3
 import (
4 4
 	"fmt"
5 5
 	"testing"
6
+
7
+	"github.com/google/pprof/profile"
6 8
 )
7 9
 
8 10
 func edgeDebugString(edge *Edge) string {
@@ -312,3 +314,87 @@ func TestTrimTree(t *testing.T) {
312 314
 		}
313 315
 	}
314 316
 }
317
+
318
+func nodeTestProfile() *profile.Profile {
319
+	mappings := []*profile.Mapping{
320
+		{
321
+			ID:   1,
322
+			File: "symbolized_binary",
323
+		},
324
+		{
325
+			ID:   2,
326
+			File: "unsymbolized_library_1",
327
+		},
328
+		{
329
+			ID:   3,
330
+			File: "unsymbolized_library_2",
331
+		},
332
+	}
333
+	functions := []*profile.Function{
334
+		{ID: 1, Name: "symname"},
335
+		{ID: 2},
336
+	}
337
+	locations := []*profile.Location{
338
+		{
339
+			ID:      1,
340
+			Mapping: mappings[0],
341
+			Line: []profile.Line{
342
+				{Function: functions[0]},
343
+			},
344
+		},
345
+		{
346
+			ID:      2,
347
+			Mapping: mappings[1],
348
+			Line: []profile.Line{
349
+				{Function: functions[1]},
350
+			},
351
+		},
352
+		{
353
+			ID:      3,
354
+			Mapping: mappings[2],
355
+		},
356
+	}
357
+	return &profile.Profile{
358
+		PeriodType: &profile.ValueType{Type: "cpu", Unit: "milliseconds"},
359
+		SampleType: []*profile.ValueType{
360
+			{Type: "type", Unit: "unit"},
361
+		},
362
+		Sample: []*profile.Sample{
363
+			{
364
+				Location: []*profile.Location{locations[0]},
365
+				Value:    []int64{1},
366
+			},
367
+			{
368
+				Location: []*profile.Location{locations[1]},
369
+				Value:    []int64{1},
370
+			},
371
+			{
372
+				Location: []*profile.Location{locations[2]},
373
+				Value:    []int64{1},
374
+			},
375
+		},
376
+		Location: locations,
377
+		Function: functions,
378
+		Mapping:  mappings,
379
+	}
380
+}
381
+
382
+// Check that nodes are properly created for a simple profile.
383
+func TestCreateNodes(t *testing.T) {
384
+	testProfile := nodeTestProfile()
385
+	wantNodeSet := NodeSet{
386
+		{Name: "symname"}:                   true,
387
+		{Objfile: "unsymbolized_library_1"}: true,
388
+		{Objfile: "unsymbolized_library_2"}: true,
389
+	}
390
+
391
+	nodes, _ := CreateNodes(testProfile, &Options{})
392
+	if len(nodes) != len(wantNodeSet) {
393
+		t.Errorf("got %d nodes, want %d", len(nodes), len(wantNodeSet))
394
+	}
395
+	for _, node := range nodes {
396
+		if !wantNodeSet[node.Info] {
397
+			t.Errorf("unexpected node %v", node.Info)
398
+		}
399
+	}
400
+}