1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package profile
16
17 import (
18 "bytes"
19 "fmt"
20 "reflect"
21 "strconv"
22 "strings"
23 "testing"
24 )
25
26 func TestLegacyProfileType(t *testing.T) {
27 type testcase struct {
28 sampleTypes []string
29 typeSet [][]string
30 want bool
31 setName string
32 }
33
34 heap := heapzSampleTypes
35 cont := contentionzSampleTypes
36 testcases := []testcase{
37
38 {[]string{"allocations", "size"}, heap, true, "heapzSampleTypes"},
39 {[]string{"objects", "space"}, heap, true, "heapzSampleTypes"},
40 {[]string{"inuse_objects", "inuse_space"}, heap, true, "heapzSampleTypes"},
41 {[]string{"alloc_objects", "alloc_space"}, heap, true, "heapzSampleTypes"},
42 {[]string{"alloc_objects", "alloc_space", "inuse_objects", "inuse_space"}, heap, true, "heapzSampleTypes"},
43 {[]string{"contentions", "delay"}, cont, true, "contentionzSampleTypes"},
44
45 {[]string{"objects"}, heap, false, "heapzSampleTypes"},
46 {[]string{"objects", "unknown"}, heap, false, "heapzSampleTypes"},
47 {[]string{"inuse_objects", "inuse_space", "alloc_objects", "alloc_space"}, heap, false, "heapzSampleTypes"},
48 {[]string{"contentions", "delay"}, heap, false, "heapzSampleTypes"},
49 {[]string{"samples", "cpu"}, heap, false, "heapzSampleTypes"},
50 {[]string{"samples", "cpu"}, cont, false, "contentionzSampleTypes"},
51 }
52
53 for _, tc := range testcases {
54 p := profileOfType(tc.sampleTypes)
55 if got := isProfileType(p, tc.typeSet); got != tc.want {
56 t.Error("isProfileType({"+strings.Join(tc.sampleTypes, ",")+"},", tc.setName, "), got", got, "want", tc.want)
57 }
58 }
59 }
60
61 func TestCpuParse(t *testing.T) {
62
63
64
65 profileString := "1:3:100:999:100:"
66 profileString += "1:5:200:999:200:501:502:"
67 profileString += "1:12:300:999:300:601:602:603:604:605:606:607:608:609:"
68 profileString += "0:1:0000"
69
70 p, err := cpuProfile([]byte(profileString), 1, parseString)
71 if err != nil {
72 t.Fatal(err)
73 }
74
75 if err := checkTestSample(p, []uint64{100}); err != nil {
76 t.Error(err)
77 }
78 if err := checkTestSample(p, []uint64{200, 500, 501}); err != nil {
79 t.Error(err)
80 }
81 if err := checkTestSample(p, []uint64{300, 600, 601, 602, 603, 604, 605, 606, 607, 608}); err != nil {
82 t.Error(err)
83 }
84 }
85
86 func parseString(b []byte) (uint64, []byte) {
87 slices := bytes.SplitN(b, []byte(":"), 2)
88 var value, remainder []byte
89 if len(slices) > 0 {
90 value = slices[0]
91 }
92 if len(slices) > 1 {
93 remainder = slices[1]
94 }
95 v, _ := strconv.ParseUint(string(value), 10, 64)
96 return v, remainder
97 }
98
99 func checkTestSample(p *Profile, want []uint64) error {
100 for _, s := range p.Sample {
101 got := []uint64{}
102 for _, l := range s.Location {
103 got = append(got, l.Address)
104 }
105 if reflect.DeepEqual(got, want) {
106 return nil
107 }
108 }
109 return fmt.Errorf("Could not find sample : %v", want)
110 }
111
112
113
114 func profileOfType(sampleTypes []string) *Profile {
115 p := new(Profile)
116 p.SampleType = make([]*ValueType, len(sampleTypes))
117 for i, t := range sampleTypes {
118 p.SampleType[i] = new(ValueType)
119 p.SampleType[i].Type = t
120 }
121 return p
122 }
123
124 func TestParseMappingEntry(t *testing.T) {
125 for _, test := range []*struct {
126 entry string
127 want *Mapping
128 }{
129 {
130 entry: "00400000-02e00000 r-xp 00000000 00:00 0",
131 want: &Mapping{
132 Start: 0x400000,
133 Limit: 0x2e00000,
134 },
135 },
136 {
137 entry: "02e00000-02e8a000 r-xp 02a00000 00:00 15953927 /foo/bin",
138 want: &Mapping{
139 Start: 0x2e00000,
140 Limit: 0x2e8a000,
141 Offset: 0x2a00000,
142 File: "/foo/bin",
143 },
144 },
145 {
146 entry: "02e00000-02e8a000 r-xp 000000 00:00 15953927 [vdso]",
147 want: &Mapping{
148 Start: 0x2e00000,
149 Limit: 0x2e8a000,
150 File: "[vdso]",
151 },
152 },
153 {
154 entry: " 02e00000-02e8a000: /foo/bin (@2a00000)",
155 want: &Mapping{
156 Start: 0x2e00000,
157 Limit: 0x2e8a000,
158 Offset: 0x2a00000,
159 File: "/foo/bin",
160 },
161 },
162 {
163 entry: " 02e00000-02e8a000: /foo/bin (deleted)",
164 want: &Mapping{
165 Start: 0x2e00000,
166 Limit: 0x2e8a000,
167 File: "/foo/bin",
168 },
169 },
170 {
171 entry: " 02e00000-02e8a000: /foo/bin",
172 want: &Mapping{
173 Start: 0x2e00000,
174 Limit: 0x2e8a000,
175 File: "/foo/bin",
176 },
177 },
178 {
179 entry: " 02e00000-02e8a000: [vdso]",
180 want: &Mapping{
181 Start: 0x2e00000,
182 Limit: 0x2e8a000,
183 File: "[vdso]",
184 },
185 },
186 {entry: "0xff6810563000 0xff6810565000 r-xp abc_exe 87c4d547f895cfd6a370e08dc5c5ee7bd4199d5b",
187 want: &Mapping{
188 Start: 0xff6810563000,
189 Limit: 0xff6810565000,
190 File: "abc_exe",
191 BuildID: "87c4d547f895cfd6a370e08dc5c5ee7bd4199d5b",
192 },
193 },
194 {entry: "7f5e5435e000-7f5e5455e000 --xp 00002000 00:00 1531 myprogram",
195 want: &Mapping{
196 Start: 0x7f5e5435e000,
197 Limit: 0x7f5e5455e000,
198 Offset: 0x2000,
199 File: "myprogram",
200 },
201 },
202 {entry: "7f7472710000-7f7472722000 r-xp 00000000 fc:00 790190 /usr/lib/libfantastic-1.2.so",
203 want: &Mapping{
204 Start: 0x7f7472710000,
205 Limit: 0x7f7472722000,
206 File: "/usr/lib/libfantastic-1.2.so",
207 },
208 },
209 {entry: "7f47a542f000-7f47a5447000: /lib/libpthread-2.15.so",
210 want: &Mapping{
211 Start: 0x7f47a542f000,
212 Limit: 0x7f47a5447000,
213 File: "/lib/libpthread-2.15.so",
214 },
215 },
216 {entry: "0x40000-0x80000 /path/to/binary (@FF00) abc123456",
217 want: &Mapping{
218 Start: 0x40000,
219 Limit: 0x80000,
220 File: "/path/to/binary",
221 Offset: 0xFF00,
222 BuildID: "abc123456",
223 },
224 },
225 {entry: "W1220 15:07:15.201776 8272 logger.cc:12033] --- Memory map: ---\n" +
226 "0x40000-0x80000 /path/to/binary (@FF00) abc123456",
227 want: &Mapping{
228 Start: 0x40000,
229 Limit: 0x80000,
230 File: "/path/to/binary",
231 Offset: 0xFF00,
232 BuildID: "abc123456",
233 },
234 },
235 {entry: "W1220 15:07:15.201776 8272 logger.cc:12033] --- Memory map: ---\n" +
236 "W1220 15:07:15.202776 8272 logger.cc:12036] 0x40000-0x80000 /path/to/binary (@FF00) abc123456",
237 want: &Mapping{
238 Start: 0x40000,
239 Limit: 0x80000,
240 File: "/path/to/binary",
241 Offset: 0xFF00,
242 BuildID: "abc123456",
243 },
244 },
245 {entry: "7f5e5435e000-7f5e5455e000 ---p 00002000 00:00 1531 myprogram",
246 want: nil,
247 },
248 } {
249 got, err := ParseProcMaps(strings.NewReader(test.entry))
250 if err != nil {
251 t.Errorf("%s: %v", test.entry, err)
252 continue
253 }
254 if test.want == nil {
255 if got, want := len(got), 0; got != want {
256 t.Errorf("%s: got %d mappings, want %d", test.entry, got, want)
257 }
258 continue
259 }
260 if got, want := len(got), 1; got != want {
261 t.Errorf("%s: got %d mappings, want %d", test.entry, got, want)
262 continue
263 }
264 if !reflect.DeepEqual(test.want, got[0]) {
265 t.Errorf("%s want=%v got=%v", test.entry, test.want, got[0])
266 }
267 }
268 }
269
270 func TestParseThreadProfileWithInvalidAddress(t *testing.T) {
271 profile := `
272 --- threadz 1 ---
273
274 --- Thread 7eff063d9940 (name: main/25376) stack: ---
275 PC: 0x40b688 0x4d5f51 0x40be31 0x473add693e639c6f0
276 --- Memory map: ---
277 00400000-00fcb000: /home/rsilvera/cppbench/cppbench_server_main.unstripped
278 `
279 wantErr := "failed to parse as hex 64-bit number: 0x473add693e639c6f0"
280 if _, gotErr := parseThread([]byte(profile)); !strings.Contains(gotErr.Error(), wantErr) {
281 t.Errorf("parseThread(): got error %q, want error containing %q", gotErr, wantErr)
282 }
283 }
284
285 func TestParseGoCount(t *testing.T) {
286 for _, test := range []struct {
287 in string
288 typ string
289 }{
290 {
291 in: `# ignored comment
292
293 threadcreate profile: total 123
294 `,
295 typ: "threadcreate",
296 },
297 {
298 in: `
299 # ignored comment
300 goroutine profile: total 123456
301 `,
302 typ: "goroutine",
303 },
304 {
305 in: `
306 sub/dir-ect_o.ry profile: total 999
307 `,
308 typ: "sub/dir-ect_o.ry",
309 },
310 } {
311 t.Run(test.typ, func(t *testing.T) {
312 p, err := parseGoCount([]byte(test.in))
313 if err != nil {
314 t.Fatalf("parseGoCount(%q) = %v", test.in, err)
315 }
316 if typ := p.PeriodType.Type; typ != test.typ {
317 t.Fatalf("parseGoCount(%q).PeriodType.Type = %q want %q", test.in, typ, test.typ)
318 }
319 })
320 }
321 }
322
View as plain text