golang.org/toolchain@v0.0.1-go1.9rc2.windows-amd64/src/cmd/vendor/github.com/google/pprof/internal/symbolizer/symbolizer_test.go (about)

     1  // Copyright 2014 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package symbolizer
    16  
    17  import (
    18  	"fmt"
    19  	"regexp"
    20  	"strings"
    21  	"testing"
    22  
    23  	"github.com/google/pprof/internal/plugin"
    24  	"github.com/google/pprof/internal/proftest"
    25  	"github.com/google/pprof/profile"
    26  )
    27  
    28  var testM = []*profile.Mapping{
    29  	{
    30  		ID:    1,
    31  		Start: 0x1000,
    32  		Limit: 0x5000,
    33  		File:  "mapping",
    34  	},
    35  }
    36  
    37  var testL = []*profile.Location{
    38  	{
    39  		ID:      1,
    40  		Mapping: testM[0],
    41  		Address: 1000,
    42  	},
    43  	{
    44  		ID:      2,
    45  		Mapping: testM[0],
    46  		Address: 2000,
    47  	},
    48  	{
    49  		ID:      3,
    50  		Mapping: testM[0],
    51  		Address: 3000,
    52  	},
    53  	{
    54  		ID:      4,
    55  		Mapping: testM[0],
    56  		Address: 4000,
    57  	},
    58  	{
    59  		ID:      5,
    60  		Mapping: testM[0],
    61  		Address: 5000,
    62  	},
    63  }
    64  
    65  var testProfile = profile.Profile{
    66  	DurationNanos: 10e9,
    67  	SampleType: []*profile.ValueType{
    68  		{Type: "cpu", Unit: "cycles"},
    69  	},
    70  	Sample: []*profile.Sample{
    71  		{
    72  			Location: []*profile.Location{testL[0]},
    73  			Value:    []int64{1},
    74  		},
    75  		{
    76  			Location: []*profile.Location{testL[1], testL[0]},
    77  			Value:    []int64{10},
    78  		},
    79  		{
    80  			Location: []*profile.Location{testL[2], testL[0]},
    81  			Value:    []int64{100},
    82  		},
    83  		{
    84  			Location: []*profile.Location{testL[3], testL[0]},
    85  			Value:    []int64{1},
    86  		},
    87  		{
    88  			Location: []*profile.Location{testL[4], testL[3], testL[0]},
    89  			Value:    []int64{10000},
    90  		},
    91  	},
    92  	Location:   testL,
    93  	Mapping:    testM,
    94  	PeriodType: &profile.ValueType{Type: "cpu", Unit: "milliseconds"},
    95  	Period:     10,
    96  }
    97  
    98  func TestSymbolization(t *testing.T) {
    99  	sSym := symbolzSymbolize
   100  	lSym := localSymbolize
   101  	defer func() {
   102  		symbolzSymbolize = sSym
   103  		localSymbolize = lSym
   104  	}()
   105  	symbolzSymbolize = symbolzMock
   106  	localSymbolize = localMock
   107  
   108  	type testcase struct {
   109  		mode        string
   110  		wantComment string
   111  	}
   112  
   113  	s := Symbolizer{
   114  		mockObjTool{},
   115  		&proftest.TestUI{T: t},
   116  	}
   117  	for i, tc := range []testcase{
   118  		{
   119  			"local",
   120  			"local=local",
   121  		},
   122  		{
   123  			"fastlocal",
   124  			"local=fastlocal",
   125  		},
   126  		{
   127  			"remote",
   128  			"symbolz",
   129  		},
   130  		{
   131  			"",
   132  			"local=:symbolz",
   133  		},
   134  	} {
   135  		prof := testProfile.Copy()
   136  		if err := s.Symbolize(tc.mode, nil, prof); err != nil {
   137  			t.Errorf("symbolize #%d: %v", i, err)
   138  			continue
   139  		}
   140  		if got, want := strings.Join(prof.Comments, ":"), tc.wantComment; got != want {
   141  			t.Errorf("got %s, want %s", got, want)
   142  			continue
   143  		}
   144  	}
   145  }
   146  
   147  func symbolzMock(sources plugin.MappingSources, syms func(string, string) ([]byte, error), p *profile.Profile, ui plugin.UI) error {
   148  	p.Comments = append(p.Comments, "symbolz")
   149  	return nil
   150  }
   151  
   152  func localMock(mode string, p *profile.Profile, obj plugin.ObjTool, ui plugin.UI) error {
   153  	p.Comments = append(p.Comments, "local="+mode)
   154  	return nil
   155  }
   156  
   157  func TestLocalSymbolization(t *testing.T) {
   158  	prof := testProfile.Copy()
   159  
   160  	if prof.HasFunctions() {
   161  		t.Error("unexpected function names")
   162  	}
   163  	if prof.HasFileLines() {
   164  		t.Error("unexpected filenames or line numbers")
   165  	}
   166  
   167  	b := mockObjTool{}
   168  	if err := localSymbolize("", prof, b, &proftest.TestUI{T: t}); err != nil {
   169  		t.Fatalf("localSymbolize(): %v", err)
   170  	}
   171  
   172  	for _, loc := range prof.Location {
   173  		if err := checkSymbolizedLocation(loc.Address, loc.Line); err != nil {
   174  			t.Errorf("location %d: %v", loc.Address, err)
   175  		}
   176  	}
   177  	if !prof.HasFunctions() {
   178  		t.Error("missing function names")
   179  	}
   180  	if !prof.HasFileLines() {
   181  		t.Error("missing filenames or line numbers")
   182  	}
   183  }
   184  
   185  func checkSymbolizedLocation(a uint64, got []profile.Line) error {
   186  	want, ok := mockAddresses[a]
   187  	if !ok {
   188  		return fmt.Errorf("unexpected address")
   189  	}
   190  	if len(want) != len(got) {
   191  		return fmt.Errorf("want len %d, got %d", len(want), len(got))
   192  	}
   193  
   194  	for i, w := range want {
   195  		g := got[i]
   196  		if g.Function.Name != w.Func {
   197  			return fmt.Errorf("want function: %q, got %q", w.Func, g.Function.Name)
   198  		}
   199  		if g.Function.Filename != w.File {
   200  			return fmt.Errorf("want filename: %q, got %q", w.File, g.Function.Filename)
   201  		}
   202  		if g.Line != int64(w.Line) {
   203  			return fmt.Errorf("want lineno: %d, got %d", w.Line, g.Line)
   204  		}
   205  	}
   206  	return nil
   207  }
   208  
   209  var mockAddresses = map[uint64][]plugin.Frame{
   210  	1000: []plugin.Frame{frame("fun11", "file11.src", 10)},
   211  	2000: []plugin.Frame{frame("fun21", "file21.src", 20), frame("fun22", "file22.src", 20)},
   212  	3000: []plugin.Frame{frame("fun31", "file31.src", 30), frame("fun32", "file32.src", 30), frame("fun33", "file33.src", 30)},
   213  	4000: []plugin.Frame{frame("fun41", "file41.src", 40), frame("fun42", "file42.src", 40), frame("fun43", "file43.src", 40), frame("fun44", "file44.src", 40)},
   214  	5000: []plugin.Frame{frame("fun51", "file51.src", 50), frame("fun52", "file52.src", 50), frame("fun53", "file53.src", 50), frame("fun54", "file54.src", 50), frame("fun55", "file55.src", 50)},
   215  }
   216  
   217  func frame(fname, file string, line int) plugin.Frame {
   218  	return plugin.Frame{
   219  		Func: fname,
   220  		File: file,
   221  		Line: line}
   222  }
   223  
   224  type mockObjTool struct{}
   225  
   226  func (mockObjTool) Open(file string, start, limit, offset uint64) (plugin.ObjFile, error) {
   227  	return mockObjFile{frames: mockAddresses}, nil
   228  }
   229  
   230  func (mockObjTool) Disasm(file string, start, end uint64) ([]plugin.Inst, error) {
   231  	return nil, fmt.Errorf("disassembly not supported")
   232  }
   233  
   234  type mockObjFile struct {
   235  	frames map[uint64][]plugin.Frame
   236  }
   237  
   238  func (mockObjFile) Name() string {
   239  	return ""
   240  }
   241  
   242  func (mockObjFile) Base() uint64 {
   243  	return 0
   244  }
   245  
   246  func (mockObjFile) BuildID() string {
   247  	return ""
   248  }
   249  
   250  func (mf mockObjFile) SourceLine(addr uint64) ([]plugin.Frame, error) {
   251  	return mf.frames[addr], nil
   252  }
   253  
   254  func (mockObjFile) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, error) {
   255  	return []*plugin.Sym{}, nil
   256  }
   257  
   258  func (mockObjFile) Close() error {
   259  	return nil
   260  }