Procházet zdrojové kódy

Create a fake mapping for profile.proto profiles (#135)

* Create a fake mapping for profile.proto profiles

If a profile has mappings but no profiles, pprof may be unable to
symbolize it offline, as it uses the mappings to keep track of which
locations need symbolization.

This fixes #120.

Added the test, verified it fails on Mac with Go 1.7 before the fix, and
passes with the fix. The test is done by augmenting the existing test
for handling https+insecure:// schema in URLs. This is a bit vague but I
figured that this test needed an updated anyway since as we moved it
recently we stopped exercising the symbolization as part of the test
which was its original intention in fixing #94. Can split the tests if
things do look too ugly.

* Fix the test to include the failed regex matching error in the message.
Alexey Alexandrov před 8 roky
rodič
revize
1047541c19

+ 11
- 11
internal/driver/fetch.go Zobrazit soubor

@@ -373,20 +373,20 @@ mapping:
373 373
 			}
374 374
 		}
375 375
 	}
376
+	if len(p.Mapping) == 0 {
377
+		// If there are no mappings, add a fake mapping to attempt symbolization.
378
+		// This is useful for some profiles generated by the golang runtime, which
379
+		// do not include any mappings. Symbolization with a fake mapping will only
380
+		// be successful against a non-PIE binary.
381
+		m := &profile.Mapping{ID: 1}
382
+		p.Mapping = []*profile.Mapping{m}
383
+		for _, l := range p.Location {
384
+			l.Mapping = m
385
+		}
386
+	}
376 387
 	// Replace executable filename/buildID with the overrides from source.
377 388
 	// Assumes the executable is the first Mapping entry.
378 389
 	if execName, buildID := s.ExecName, s.BuildID; execName != "" || buildID != "" {
379
-		if len(p.Mapping) == 0 {
380
-			// If there are no mappings, add a fake mapping to attempt symbolization.
381
-			// This is useful for some profiles generated by the golang runtime, which
382
-			// do not include any mappings. Symbolization with a fake mapping will only
383
-			// be successful against a non-PIE binary.
384
-			m := &profile.Mapping{ID: 1}
385
-			p.Mapping = []*profile.Mapping{m}
386
-			for _, l := range p.Location {
387
-				l.Mapping = m
388
-			}
389
-		}
390 390
 		m := p.Mapping[0]
391 391
 		if execName != "" {
392 392
 			m.File = execName

+ 27
- 2
internal/driver/fetch_test.go Zobrazit soubor

@@ -35,8 +35,10 @@ import (
35 35
 	"testing"
36 36
 	"time"
37 37
 
38
+	"github.com/google/pprof/internal/binutils"
38 39
 	"github.com/google/pprof/internal/plugin"
39 40
 	"github.com/google/pprof/internal/proftest"
41
+	"github.com/google/pprof/internal/symbolizer"
40 42
 	"github.com/google/pprof/profile"
41 43
 )
42 44
 
@@ -275,14 +277,37 @@ func TestHttpsInsecure(t *testing.T) {
275 277
 	defer os.Remove(outputTempFile.Name())
276 278
 	defer outputTempFile.Close()
277 279
 
278
-	address := "https+insecure://" + l.Addr().String() + "/debug/pprof/profile?seconds=5"
279
-	p, _, _, err := grabProfile(&source{}, address, 0, nil, testObj{}, &proftest.TestUI{T: t})
280
+	address := "https+insecure://" + l.Addr().String() + "/debug/pprof/profile"
281
+	s := &source{
282
+		Sources:   []string{address},
283
+		Seconds:   10,
284
+		Timeout:   10,
285
+		Symbolize: "remote",
286
+	}
287
+	o := &plugin.Options{
288
+		Obj: &binutils.Binutils{},
289
+		UI:  &proftest.TestUI{T: t, IgnoreRx: "Saved profile in"},
290
+	}
291
+	o.Sym = &symbolizer.Symbolizer{Obj: o.Obj, UI: o.UI}
292
+	p, err := fetchProfiles(s, o)
280 293
 	if err != nil {
281 294
 		t.Fatal(err)
282 295
 	}
283 296
 	if len(p.SampleType) == 0 {
284 297
 		t.Fatalf("grabProfile(%s) got empty profile: len(p.SampleType)==0", address)
285 298
 	}
299
+	if err := checkProfileHasFunction(p, "TestHttpsInsecure"); err != nil {
300
+		t.Fatalf("grabProfile(%s) %v", address, err)
301
+	}
302
+}
303
+
304
+func checkProfileHasFunction(p *profile.Profile, fname string) error {
305
+	for _, f := range p.Function {
306
+		if strings.Contains(f.Name, fname) {
307
+			return nil
308
+		}
309
+	}
310
+	return fmt.Errorf("got %s, want function %q", p.String(), fname)
286 311
 }
287 312
 
288 313
 func selfSignedCert(t *testing.T) tls.Certificate {

+ 13
- 3
internal/proftest/proftest.go Zobrazit soubor

@@ -22,6 +22,7 @@ import (
22 22
 	"io/ioutil"
23 23
 	"os"
24 24
 	"os/exec"
25
+	"regexp"
25 26
 	"testing"
26 27
 )
27 28
 
@@ -71,10 +72,11 @@ func EncodeJSON(x interface{}) []byte {
71 72
 }
72 73
 
73 74
 // TestUI implements the plugin.UI interface, triggering test failures
74
-// if more than Ignore errors are printed.
75
+// if more than Ignore errors not matching IgnoreRx are printed.
75 76
 type TestUI struct {
76
-	T      *testing.T
77
-	Ignore int
77
+	T        *testing.T
78
+	Ignore   int
79
+	IgnoreRx string
78 80
 }
79 81
 
80 82
 // ReadLine returns no input, as no input is expected during testing.
@@ -89,6 +91,14 @@ func (ui *TestUI) Print(args ...interface{}) {
89 91
 // PrintErr messages may trigger an error failure. A fixed number of
90 92
 // error messages are permitted when appropriate.
91 93
 func (ui *TestUI) PrintErr(args ...interface{}) {
94
+	if ui.IgnoreRx != "" {
95
+		if matched, err := regexp.MatchString(ui.IgnoreRx, fmt.Sprint(args)); matched || err != nil {
96
+			if err != nil {
97
+				ui.T.Errorf("failed to match against regex %q: %v", ui.IgnoreRx, err)
98
+			}
99
+			return
100
+		}
101
+	}
92 102
 	if ui.Ignore > 0 {
93 103
 		ui.Ignore--
94 104
 		return