Ei kuvausta

symbolizer_test.go 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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. package symbolizer
  15. import (
  16. "fmt"
  17. "regexp"
  18. "strings"
  19. "testing"
  20. "github.com/google/pprof/internal/plugin"
  21. "github.com/google/pprof/internal/proftest"
  22. "github.com/google/pprof/profile"
  23. )
  24. var testM = []*profile.Mapping{
  25. {
  26. ID: 1,
  27. Start: 0x1000,
  28. Limit: 0x5000,
  29. File: "mapping",
  30. },
  31. }
  32. var testL = []*profile.Location{
  33. {
  34. ID: 1,
  35. Mapping: testM[0],
  36. Address: 1000,
  37. },
  38. {
  39. ID: 2,
  40. Mapping: testM[0],
  41. Address: 2000,
  42. },
  43. {
  44. ID: 3,
  45. Mapping: testM[0],
  46. Address: 3000,
  47. },
  48. {
  49. ID: 4,
  50. Mapping: testM[0],
  51. Address: 4000,
  52. },
  53. {
  54. ID: 5,
  55. Mapping: testM[0],
  56. Address: 5000,
  57. },
  58. }
  59. var testProfile = profile.Profile{
  60. DurationNanos: 10e9,
  61. SampleType: []*profile.ValueType{
  62. {Type: "cpu", Unit: "cycles"},
  63. },
  64. Sample: []*profile.Sample{
  65. {
  66. Location: []*profile.Location{testL[0]},
  67. Value: []int64{1},
  68. },
  69. {
  70. Location: []*profile.Location{testL[1], testL[0]},
  71. Value: []int64{10},
  72. },
  73. {
  74. Location: []*profile.Location{testL[2], testL[0]},
  75. Value: []int64{100},
  76. },
  77. {
  78. Location: []*profile.Location{testL[3], testL[0]},
  79. Value: []int64{1},
  80. },
  81. {
  82. Location: []*profile.Location{testL[4], testL[3], testL[0]},
  83. Value: []int64{10000},
  84. },
  85. },
  86. Location: testL,
  87. Mapping: testM,
  88. PeriodType: &profile.ValueType{Type: "cpu", Unit: "milliseconds"},
  89. Period: 10,
  90. }
  91. func TestSymbolization(t *testing.T) {
  92. sSym := symbolzSymbolize
  93. lSym := localSymbolize
  94. defer func() {
  95. symbolzSymbolize = sSym
  96. localSymbolize = lSym
  97. }()
  98. symbolzSymbolize = symbolzMock
  99. localSymbolize = localMock
  100. type testcase struct {
  101. mode string
  102. wantComment string
  103. }
  104. s := Symbolizer{
  105. mockObjTool{},
  106. &proftest.TestUI{T: t},
  107. }
  108. for i, tc := range []testcase{
  109. {
  110. "local",
  111. "local=local",
  112. },
  113. {
  114. "fastlocal",
  115. "local=fastlocal",
  116. },
  117. {
  118. "remote",
  119. "symbolz",
  120. },
  121. {
  122. "",
  123. "local=:symbolz",
  124. },
  125. } {
  126. prof := testProfile.Copy()
  127. if err := s.Symbolize(tc.mode, nil, prof); err != nil {
  128. t.Errorf("symbolize #%d: %v", i, err)
  129. continue
  130. }
  131. if got, want := strings.Join(prof.Comments, ":"), tc.wantComment; got != want {
  132. t.Errorf("got %s, want %s", got, want)
  133. continue
  134. }
  135. }
  136. }
  137. func symbolzMock(sources plugin.MappingSources, syms func(string, string) ([]byte, error), p *profile.Profile, ui plugin.UI) error {
  138. p.Comments = append(p.Comments, "symbolz")
  139. return nil
  140. }
  141. func localMock(mode string, p *profile.Profile, obj plugin.ObjTool, ui plugin.UI) error {
  142. p.Comments = append(p.Comments, "local="+mode)
  143. return nil
  144. }
  145. func TestLocalSymbolization(t *testing.T) {
  146. prof := testProfile.Copy()
  147. if prof.HasFunctions() {
  148. t.Error("unexpected function names")
  149. }
  150. if prof.HasFileLines() {
  151. t.Error("unexpected filenames or line numbers")
  152. }
  153. b := mockObjTool{}
  154. if err := localSymbolize("", prof, b, &proftest.TestUI{T: t}); err != nil {
  155. t.Fatalf("localSymbolize(): %v", err)
  156. }
  157. for _, loc := range prof.Location {
  158. if err := checkSymbolizedLocation(loc.Address, loc.Line); err != nil {
  159. t.Errorf("location %d: %v", loc.Address, err)
  160. }
  161. }
  162. if !prof.HasFunctions() {
  163. t.Error("missing function names")
  164. }
  165. if !prof.HasFileLines() {
  166. t.Error("missing filenames or line numbers")
  167. }
  168. }
  169. func checkSymbolizedLocation(a uint64, got []profile.Line) error {
  170. want, ok := mockAddresses[a]
  171. if !ok {
  172. return fmt.Errorf("unexpected address")
  173. }
  174. if len(want) != len(got) {
  175. return fmt.Errorf("want len %d, got %d", len(want), len(got))
  176. }
  177. for i, w := range want {
  178. g := got[i]
  179. if g.Function.Name != w.Func {
  180. return fmt.Errorf("want function: %q, got %q", w.Func, g.Function.Name)
  181. }
  182. if g.Function.Filename != w.File {
  183. return fmt.Errorf("want filename: %q, got %q", w.File, g.Function.Filename)
  184. }
  185. if g.Line != int64(w.Line) {
  186. return fmt.Errorf("want lineno: %d, got %d", w.Line, g.Line)
  187. }
  188. }
  189. return nil
  190. }
  191. var mockAddresses = map[uint64][]plugin.Frame{
  192. 1000: []plugin.Frame{frame("fun11", "file11.src", 10)},
  193. 2000: []plugin.Frame{frame("fun21", "file21.src", 20), frame("fun22", "file22.src", 20)},
  194. 3000: []plugin.Frame{frame("fun31", "file31.src", 30), frame("fun32", "file32.src", 30), frame("fun33", "file33.src", 30)},
  195. 4000: []plugin.Frame{frame("fun41", "file41.src", 40), frame("fun42", "file42.src", 40), frame("fun43", "file43.src", 40), frame("fun44", "file44.src", 40)},
  196. 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)},
  197. }
  198. func frame(fname, file string, line int) plugin.Frame {
  199. return plugin.Frame{
  200. Func: fname,
  201. File: file,
  202. Line: line}
  203. }
  204. type mockObjTool struct{}
  205. func (mockObjTool) Open(file string, start, limit, offset uint64) (plugin.ObjFile, error) {
  206. return mockObjFile{frames: mockAddresses}, nil
  207. }
  208. func (mockObjTool) Disasm(file string, start, end uint64) ([]plugin.Inst, error) {
  209. return nil, fmt.Errorf("disassembly not supported")
  210. }
  211. type mockObjFile struct {
  212. frames map[uint64][]plugin.Frame
  213. }
  214. func (mockObjFile) Name() string {
  215. return ""
  216. }
  217. func (mockObjFile) Base() uint64 {
  218. return 0
  219. }
  220. func (mockObjFile) BuildID() string {
  221. return ""
  222. }
  223. func (mf mockObjFile) SourceLine(addr uint64) ([]plugin.Frame, error) {
  224. return mf.frames[addr], nil
  225. }
  226. func (mockObjFile) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, error) {
  227. return []*plugin.Sym{}, nil
  228. }
  229. func (mockObjFile) Close() error {
  230. return nil
  231. }