• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "sample_info_reader.h"
6 
7 #include <byteswap.h>
8 
9 #include "compat/test.h"
10 #include "kernel/perf_event.h"
11 #include "kernel/perf_internals.h"
12 #include "test_perf_data.h"
13 #include "test_utils.h"
14 
15 namespace quipper {
16 
17 using testing::PunU32U64;
18 
TEST(SampleInfoReaderTest,ReadSampleEvent)19 TEST(SampleInfoReaderTest, ReadSampleEvent) {
20   // clang-format off
21   uint64_t sample_type =       // * == in sample_id_all
22       PERF_SAMPLE_IP |
23       PERF_SAMPLE_TID |        // *
24       PERF_SAMPLE_TIME |       // *
25       PERF_SAMPLE_ADDR |
26       PERF_SAMPLE_ID |         // *
27       PERF_SAMPLE_STREAM_ID |  // *
28       PERF_SAMPLE_CPU |        // *
29       PERF_SAMPLE_PERIOD |
30       PERF_SAMPLE_WEIGHT |
31       PERF_SAMPLE_DATA_SRC |
32       PERF_SAMPLE_TRANSACTION;
33   // clang-format on
34   struct perf_event_attr attr = {0};
35   attr.sample_type = sample_type;
36 
37   SampleInfoReader reader(attr, false /* read_cross_endian */);
38 
39   const u64 sample_event_array[] = {
40       0xffffffff01234567,                    // IP
41       PunU32U64{.v32 = {0x68d, 0x68e}}.v64,  // TID (u32 pid, tid)
42       1415837014 * 1000000000ULL,            // TIME
43       0x00007f999c38d15a,                    // ADDR
44       2,                                     // ID
45       1,                                     // STREAM_ID
46       8,                                     // CPU
47       10001,                                 // PERIOD
48       12345,                                 // WEIGHT
49       0x68100142,                            // DATA_SRC
50       67890,                                 // TRANSACTIONS
51   };
52   const sample_event sample_event_struct = {
53       .header = {
54           .type = PERF_RECORD_SAMPLE,
55           .misc = 0,
56           .size = sizeof(sample_event) + sizeof(sample_event_array),
57       }};
58 
59   std::stringstream input;
60   input.write(reinterpret_cast<const char*>(&sample_event_struct),
61               sizeof(sample_event_struct));
62   input.write(reinterpret_cast<const char*>(sample_event_array),
63               sizeof(sample_event_array));
64   string input_string = input.str();
65   const event_t& event = *reinterpret_cast<const event_t*>(input_string.data());
66 
67   perf_sample sample;
68   ASSERT_TRUE(reader.ReadPerfSampleInfo(event, &sample));
69 
70   EXPECT_EQ(0xffffffff01234567, sample.ip);
71   EXPECT_EQ(0x68d, sample.pid);
72   EXPECT_EQ(0x68e, sample.tid);
73   EXPECT_EQ(1415837014 * 1000000000ULL, sample.time);
74   EXPECT_EQ(0x00007f999c38d15a, sample.addr);
75   EXPECT_EQ(2, sample.id);
76   EXPECT_EQ(1, sample.stream_id);
77   EXPECT_EQ(8, sample.cpu);
78   EXPECT_EQ(10001, sample.period);
79   EXPECT_EQ(12345, sample.weight);
80   EXPECT_EQ(0x68100142, sample.data_src);
81   EXPECT_EQ(67890, sample.transaction);
82 }
83 
TEST(SampleInfoReaderTest,ReadSampleEventCrossEndian)84 TEST(SampleInfoReaderTest, ReadSampleEventCrossEndian) {
85   // clang-format off
86   uint64_t sample_type =      // * == in sample_id_all
87       PERF_SAMPLE_IP |
88       PERF_SAMPLE_TID |        // *
89       PERF_SAMPLE_TIME |       // *
90       PERF_SAMPLE_ADDR |
91       PERF_SAMPLE_ID |         // *
92       PERF_SAMPLE_STREAM_ID |  // *
93       PERF_SAMPLE_CPU |        // *
94       PERF_SAMPLE_PERIOD;
95   // clang-format on
96   struct perf_event_attr attr = {0};
97   attr.sample_type = sample_type;
98 
99   SampleInfoReader reader(attr, true /* read_cross_endian */);
100 
101   const u64 sample_event_array[] = {
102       0xffffffff01234567,                    // IP
103       PunU32U64{.v32 = {0x68d, 0x68e}}.v64,  // TID (u32 pid, tid)
104       1415837014 * 1000000000ULL,            // TIME
105       0x00007f999c38d15a,                    // ADDR
106       2,                                     // ID
107       1,                                     // STREAM_ID
108       8,                                     // CPU
109       10001,                                 // PERIOD
110   };
111 
112   const sample_event sample_event_struct = {
113       .header = {
114           .type = PERF_RECORD_SAMPLE,
115           .misc = 0,
116           .size = sizeof(sample_event) + sizeof(sample_event_array),
117       }};
118 
119   std::stringstream input;
120   input.write(reinterpret_cast<const char*>(&sample_event_struct),
121               sizeof(sample_event_struct));
122   input.write(reinterpret_cast<const char*>(sample_event_array),
123               sizeof(sample_event_array));
124   string input_string = input.str();
125   const event_t& event = *reinterpret_cast<const event_t*>(input_string.data());
126 
127   perf_sample sample;
128   ASSERT_TRUE(reader.ReadPerfSampleInfo(event, &sample));
129 
130   EXPECT_EQ(bswap_64(0xffffffff01234567), sample.ip);
131   EXPECT_EQ(bswap_32(0x68d), sample.pid);  // 32-bit
132   EXPECT_EQ(bswap_32(0x68e), sample.tid);  // 32-bit
133   EXPECT_EQ(bswap_64(1415837014 * 1000000000ULL), sample.time);
134   EXPECT_EQ(bswap_64(0x00007f999c38d15a), sample.addr);
135   EXPECT_EQ(bswap_64(2), sample.id);
136   EXPECT_EQ(bswap_64(1), sample.stream_id);
137   EXPECT_EQ(bswap_32(8), sample.cpu);  // 32-bit
138   EXPECT_EQ(bswap_64(10001), sample.period);
139 }
140 
TEST(SampleInfoReaderTest,ReadMmapEvent)141 TEST(SampleInfoReaderTest, ReadMmapEvent) {
142   // clang-format off
143   uint64_t sample_type =      // * == in sample_id_all
144       PERF_SAMPLE_IP |
145       PERF_SAMPLE_TID |        // *
146       PERF_SAMPLE_TIME |       // *
147       PERF_SAMPLE_ADDR |
148       PERF_SAMPLE_ID |         // *
149       PERF_SAMPLE_STREAM_ID |  // *
150       PERF_SAMPLE_CPU |        // *
151       PERF_SAMPLE_PERIOD;
152   // clang-format on
153   struct perf_event_attr attr = {0};
154   attr.sample_type = sample_type;
155   attr.sample_id_all = true;
156 
157   SampleInfoReader reader(attr, false /* read_cross_endian */);
158 
159   // PERF_RECORD_MMAP
160   ASSERT_EQ(40, offsetof(struct mmap_event, filename));
161   const u64 mmap_sample_id[] = {
162       PunU32U64{.v32 = {0x68d, 0x68e}}.v64,  // TID (u32 pid, tid)
163       1415911367 * 1000000000ULL,            // TIME
164       3,                                     // ID
165       2,                                     // STREAM_ID
166       9,                                     // CPU
167   };
168   // clang-format off
169   const size_t mmap_event_size =
170       offsetof(struct mmap_event, filename) +
171       10+6 /* ==16, nearest 64-bit boundary for filename */ +
172       sizeof(mmap_sample_id);
173   // clang-format on
174 
175   const char mmap_filename[10 + 6] = "/dev/zero";
176   struct mmap_event written_mmap_event = {
177       .header =
178           {
179               .type = PERF_RECORD_MMAP,
180               .misc = 0,
181               .size = mmap_event_size,
182           },
183       .pid = 0x68d,
184       .tid = 0x68d,
185       .start = 0x1d000,
186       .len = 0x1000,
187       .pgoff = 0,
188       // .filename = ..., // written separately
189   };
190 
191   std::stringstream input;
192   input.write(reinterpret_cast<const char*>(&written_mmap_event),
193               offsetof(struct mmap_event, filename));
194   input.write(mmap_filename, 10 + 6);
195   input.write(reinterpret_cast<const char*>(mmap_sample_id),
196               sizeof(mmap_sample_id));
197 
198   string input_string = input.str();
199   const event_t& event = *reinterpret_cast<const event_t*>(input_string.data());
200 
201   perf_sample sample;
202   ASSERT_TRUE(reader.ReadPerfSampleInfo(event, &sample));
203 
204   EXPECT_EQ(0x68d, sample.pid);
205   EXPECT_EQ(0x68e, sample.tid);
206   EXPECT_EQ(1415911367 * 1000000000ULL, sample.time);
207   EXPECT_EQ(3, sample.id);
208   EXPECT_EQ(2, sample.stream_id);
209   EXPECT_EQ(9, sample.cpu);
210 }
211 
TEST(SampleInfoReaderTest,ReadReadInfoAllFields)212 TEST(SampleInfoReaderTest, ReadReadInfoAllFields) {
213   struct perf_event_attr attr = {0};
214   attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_READ;
215   attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
216                      PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_ID;
217 
218   SampleInfoReader reader(attr, false /* read_cross_endian */);
219 
220   // PERF_RECORD_SAMPLE
221   const u64 sample_event_array[] = {
222       0xffffffff01234567,                    // IP
223       PunU32U64{.v32 = {0x68d, 0x68e}}.v64,  // TID (u32 pid, tid)
224       // From kernel/perf_event.h:
225       // struct read_format {
226       //   { u64  value;
227       //     { u64  time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED
228       //     { u64  time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING
229       //     { u64  id;           } && PERF_FORMAT_ID
230       //   } && !PERF_FORMAT_GROUP
231       // };
232       1000000,                     // READ: value
233       1415837014 * 1000000000ULL,  // READ: time_enabled
234       1234567890 * 1000000000ULL,  // READ: time_running
235       0xabcdef,                    // READ: id
236   };
237   sample_event sample_event_struct = {
238       .header = {
239           .type = PERF_RECORD_SAMPLE,
240           .misc = 0,
241           .size = sizeof(sample_event) + sizeof(sample_event_array),
242       }};
243 
244   std::stringstream input;
245   input.write(reinterpret_cast<const char*>(&sample_event_struct),
246               sizeof(sample_event_struct));
247   input.write(reinterpret_cast<const char*>(sample_event_array),
248               sizeof(sample_event_array));
249   string input_string = input.str();
250   const event_t& event = *reinterpret_cast<const event_t*>(input_string.data());
251 
252   perf_sample sample;
253   ASSERT_TRUE(reader.ReadPerfSampleInfo(event, &sample));
254 
255   EXPECT_EQ(0xffffffff01234567, sample.ip);
256   EXPECT_EQ(0x68d, sample.pid);
257   EXPECT_EQ(0x68e, sample.tid);
258   EXPECT_EQ(1415837014 * 1000000000ULL, sample.read.time_enabled);
259   EXPECT_EQ(1234567890 * 1000000000ULL, sample.read.time_running);
260   EXPECT_EQ(0xabcdef, sample.read.one.id);
261   EXPECT_EQ(1000000, sample.read.one.value);
262 }
263 
TEST(SampleInfoReaderTest,ReadReadInfoOmitTotalTimeFields)264 TEST(SampleInfoReaderTest, ReadReadInfoOmitTotalTimeFields) {
265   struct perf_event_attr attr = {0};
266   attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_READ;
267   // Omit the PERF_FORMAT_TOTAL_TIME_* fields.
268   attr.read_format = PERF_FORMAT_ID;
269 
270   SampleInfoReader reader(attr, false /* read_cross_endian */);
271 
272   // PERF_RECORD_SAMPLE
273   const u64 sample_event_array[] = {
274       0xffffffff01234567,                    // IP
275       PunU32U64{.v32 = {0x68d, 0x68e}}.v64,  // TID (u32 pid, tid)
276       1000000,                               // READ: value
277       0xabcdef,                              // READ: id
278   };
279   sample_event sample_event_struct = {
280       .header = {
281           .type = PERF_RECORD_SAMPLE,
282           .misc = 0,
283           .size = sizeof(sample_event) + sizeof(sample_event_array),
284       }};
285 
286   std::stringstream input;
287   input.write(reinterpret_cast<const char*>(&sample_event_struct),
288               sizeof(sample_event_struct));
289   input.write(reinterpret_cast<const char*>(sample_event_array),
290               sizeof(sample_event_array));
291   string input_string = input.str();
292   const event_t& event = *reinterpret_cast<const event_t*>(input_string.data());
293 
294   perf_sample sample;
295   ASSERT_TRUE(reader.ReadPerfSampleInfo(event, &sample));
296 
297   EXPECT_EQ(0xffffffff01234567, sample.ip);
298   EXPECT_EQ(0x68d, sample.pid);
299   EXPECT_EQ(0x68e, sample.tid);
300   EXPECT_EQ(0xabcdef, sample.read.one.id);
301   EXPECT_EQ(1000000, sample.read.one.value);
302 }
303 
TEST(SampleInfoReaderTest,ReadReadInfoValueFieldOnly)304 TEST(SampleInfoReaderTest, ReadReadInfoValueFieldOnly) {
305   struct perf_event_attr attr = {0};
306   attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_READ;
307   // Omit all optional fields. The |value| field still remains.
308   attr.read_format = 0;
309 
310   SampleInfoReader reader(attr, false /* read_cross_endian */);
311 
312   // PERF_RECORD_SAMPLE
313   const u64 sample_event_array[] = {
314       0xffffffff01234567,                    // IP
315       PunU32U64{.v32 = {0x68d, 0x68e}}.v64,  // TID (u32 pid, tid)
316       1000000,                               // READ: value
317   };
318   sample_event sample_event_struct = {
319       .header = {
320           .type = PERF_RECORD_SAMPLE,
321           .misc = 0,
322           .size = sizeof(sample_event) + sizeof(sample_event_array),
323       }};
324 
325   std::stringstream input;
326   input.write(reinterpret_cast<const char*>(&sample_event_struct),
327               sizeof(sample_event_struct));
328   input.write(reinterpret_cast<const char*>(sample_event_array),
329               sizeof(sample_event_array));
330   string input_string = input.str();
331   const event_t& event = *reinterpret_cast<const event_t*>(input_string.data());
332 
333   perf_sample sample;
334   ASSERT_TRUE(reader.ReadPerfSampleInfo(event, &sample));
335 
336   EXPECT_EQ(0xffffffff01234567, sample.ip);
337   EXPECT_EQ(0x68d, sample.pid);
338   EXPECT_EQ(0x68e, sample.tid);
339   EXPECT_EQ(1000000, sample.read.one.value);
340 }
341 
TEST(SampleInfoReaderTest,ReadReadInfoWithGroups)342 TEST(SampleInfoReaderTest, ReadReadInfoWithGroups) {
343   struct perf_event_attr attr = {0};
344   attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_READ;
345   // Omit the PERF_FORMAT_TOTAL_TIME_* fields.
346   attr.read_format = PERF_FORMAT_ID | PERF_FORMAT_GROUP;
347 
348   SampleInfoReader reader(attr, false /* read_cross_endian */);
349 
350   // PERF_RECORD_SAMPLE
351   const u64 sample_event_array[] = {
352       0xffffffff01234567,                    // IP
353       PunU32U64{.v32 = {0x68d, 0x68e}}.v64,  // TID (u32 pid, tid)
354       3,                                     // READ: nr
355       1000000,                               // READ: values[0].value
356       0xabcdef,                              // READ: values[0].id
357       2000000,                               // READ: values[1].value
358       0xdecaf0,                              // READ: values[1].id
359       3000000,                               // READ: values[2].value
360       0xbeef00,                              // READ: values[2].id
361   };
362   sample_event sample_event_struct = {
363       .header = {
364           .type = PERF_RECORD_SAMPLE,
365           .misc = 0,
366           .size = sizeof(sample_event) + sizeof(sample_event_array),
367       }};
368 
369   std::stringstream input;
370   input.write(reinterpret_cast<const char*>(&sample_event_struct),
371               sizeof(sample_event_struct));
372   input.write(reinterpret_cast<const char*>(sample_event_array),
373               sizeof(sample_event_array));
374   string input_string = input.str();
375   const event_t& event = *reinterpret_cast<const event_t*>(input_string.data());
376 
377   perf_sample sample;
378   ASSERT_TRUE(reader.ReadPerfSampleInfo(event, &sample));
379 
380   EXPECT_EQ(0xffffffff01234567, sample.ip);
381   EXPECT_EQ(0x68d, sample.pid);
382   EXPECT_EQ(0x68e, sample.tid);
383   EXPECT_EQ(3, sample.read.group.nr);
384   ASSERT_NE(static_cast<void*>(NULL), sample.read.group.values);
385   EXPECT_EQ(0xabcdef, sample.read.group.values[0].id);
386   EXPECT_EQ(1000000, sample.read.group.values[0].value);
387   EXPECT_EQ(0xdecaf0, sample.read.group.values[1].id);
388   EXPECT_EQ(2000000, sample.read.group.values[1].value);
389   EXPECT_EQ(0xbeef00, sample.read.group.values[2].id);
390   EXPECT_EQ(3000000, sample.read.group.values[2].value);
391 }
392 
393 }  // namespace quipper
394