1 // Copyright (c) 2012 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 <inttypes.h>
6 #include <sys/time.h>
7
8 #include <map>
9 #include <sstream>
10 #include <string>
11
12 #include "base/logging.h"
13 #include "base/macros.h"
14
15 #include "compat/string.h"
16 #include "compat/test.h"
17 #include "file_utils.h"
18 #include "perf_data_structures.h"
19 #include "perf_data_utils.h"
20 #include "perf_protobuf_io.h"
21 #include "perf_reader.h"
22 #include "perf_serializer.h"
23 #include "perf_test_files.h"
24 #include "scoped_temp_path.h"
25 #include "test_perf_data.h"
26 #include "test_utils.h"
27
28 namespace {
29
30 // Returns a string representation of an unsigned integer |value|.
UintToString(uint64_t value)31 string UintToString(uint64_t value) {
32 std::stringstream ss;
33 ss << value;
34 return ss.str();
35 }
36
37 } // namespace
38
39 namespace quipper {
40
41 using PerfEvent = PerfDataProto_PerfEvent;
42 using SampleInfo = PerfDataProto_SampleInfo;
43
44 namespace {
45
46 // Set up some parameterized fixtures for test cases that should run
47 // against multiple files.
48 class SerializePerfDataFiles : public ::testing::TestWithParam<const char*> {};
49 class SerializeAllPerfDataFiles : public ::testing::TestWithParam<const char*> {
50 };
51 class SerializePerfDataProtoFiles
52 : public ::testing::TestWithParam<const char*> {};
53
54 // Gets the timestamp from an event field in PerfDataProto.
GetSampleTimestampFromEventProto(const PerfDataProto_PerfEvent & event)55 const uint64_t GetSampleTimestampFromEventProto(
56 const PerfDataProto_PerfEvent& event) {
57 // Get SampleInfo from the correct type-specific event field for the event.
58 if (event.has_mmap_event()) {
59 return event.mmap_event().sample_info().sample_time_ns();
60 } else if (event.has_sample_event()) {
61 return event.sample_event().sample_time_ns();
62 } else if (event.has_comm_event()) {
63 return event.comm_event().sample_info().sample_time_ns();
64 } else if (event.has_fork_event()) {
65 return event.fork_event().sample_info().sample_time_ns();
66 } else if (event.has_exit_event()) {
67 return event.exit_event().sample_info().sample_time_ns();
68 } else if (event.has_lost_event()) {
69 return event.lost_event().sample_info().sample_time_ns();
70 } else if (event.has_throttle_event()) {
71 return event.throttle_event().sample_info().sample_time_ns();
72 } else if (event.has_read_event()) {
73 return event.read_event().sample_info().sample_time_ns();
74 } else if (event.has_aux_event()) {
75 return event.aux_event().sample_info().sample_time_ns();
76 }
77 return 0;
78 }
79
80 // Verifies that |proto|'s events are in chronological order. No event should
81 // have an earlier timestamp than a preceding event.
CheckChronologicalOrderOfSerializedEvents(const PerfDataProto & proto)82 void CheckChronologicalOrderOfSerializedEvents(const PerfDataProto& proto) {
83 uint64_t prev_time_ns = 0;
84 for (int i = 0; i < proto.events_size(); ++i) {
85 // Compare each timestamp against the previous event's timestamp.
86 uint64_t time_ns = GetSampleTimestampFromEventProto(proto.events(i));
87 if (i > 0) {
88 EXPECT_GE(time_ns, prev_time_ns);
89 }
90 prev_time_ns = time_ns;
91 }
92 }
93
SerializeAndDeserialize(const string & input,const string & output,bool do_remap,bool discard_unused_events)94 void SerializeAndDeserialize(const string& input, const string& output,
95 bool do_remap, bool discard_unused_events) {
96 PerfDataProto perf_data_proto;
97 PerfParserOptions options;
98 options.do_remap = do_remap;
99 options.deduce_huge_page_mappings = false;
100 options.combine_mappings = false;
101 options.discard_unused_events = discard_unused_events;
102 options.sample_mapping_percentage_threshold = 100.0f;
103
104 ASSERT_TRUE(SerializeFromFileWithOptions(input, options, &perf_data_proto));
105
106 PerfReader reader;
107 ASSERT_TRUE(reader.Deserialize(perf_data_proto));
108
109 PerfParser parser(&reader, options);
110 ASSERT_TRUE(parser.ParseRawEvents());
111
112 // Check perf event stats.
113 const PerfDataProto_PerfEventStats& in_stats = perf_data_proto.stats();
114 PerfEventStats out_stats;
115 PerfSerializer::DeserializeParserStats(perf_data_proto, &out_stats);
116
117 EXPECT_EQ(in_stats.num_sample_events(), out_stats.num_sample_events);
118 EXPECT_EQ(in_stats.num_mmap_events(), out_stats.num_mmap_events);
119 EXPECT_EQ(in_stats.num_fork_events(), out_stats.num_fork_events);
120 EXPECT_EQ(in_stats.num_exit_events(), out_stats.num_exit_events);
121 EXPECT_EQ(in_stats.num_sample_events_mapped(),
122 out_stats.num_sample_events_mapped);
123 EXPECT_EQ(do_remap, in_stats.did_remap());
124 EXPECT_EQ(do_remap, out_stats.did_remap);
125
126 ASSERT_TRUE(reader.WriteFile(output));
127 }
128
SerializeToFileAndBack(const string & input,const string & output)129 void SerializeToFileAndBack(const string& input, const string& output) {
130 struct timeval pre_serialize_time;
131 gettimeofday(&pre_serialize_time, NULL);
132
133 // Serialize with and without sorting by chronological order.
134 PerfDataProto input_perf_data_proto;
135
136 // Serialize with and without sorting by chronological order.
137 // PerfSerializer is stateless w/r to Serialize or Deserialize calls so we can
138 // use just one.
139 PerfParserOptions options;
140 options.sort_events_by_time = true;
141 options.deduce_huge_page_mappings = false;
142 options.combine_mappings = false;
143 EXPECT_TRUE(
144 SerializeFromFileWithOptions(input, options, &input_perf_data_proto));
145 CheckChronologicalOrderOfSerializedEvents(input_perf_data_proto);
146
147 input_perf_data_proto.Clear();
148 options.sort_events_by_time = false;
149 EXPECT_TRUE(
150 SerializeFromFileWithOptions(input, options, &input_perf_data_proto));
151
152 // Make sure the timestamp_sec was properly recorded.
153 EXPECT_TRUE(input_perf_data_proto.has_timestamp_sec());
154 // Check it against the current time.
155 struct timeval post_serialize_time;
156 gettimeofday(&post_serialize_time, NULL);
157 EXPECT_GE(input_perf_data_proto.timestamp_sec(), pre_serialize_time.tv_sec);
158 EXPECT_LE(input_perf_data_proto.timestamp_sec(), post_serialize_time.tv_sec);
159
160 // Now store the protobuf into a file.
161 ScopedTempFile input_file;
162 EXPECT_FALSE(input_file.path().empty());
163 string input_filename = input_file.path();
164 ScopedTempFile output_file;
165 EXPECT_FALSE(output_file.path().empty());
166 string output_filename = output_file.path();
167
168 EXPECT_TRUE(WriteProtobufToFile(input_perf_data_proto, input_filename));
169
170 PerfDataProto output_perf_data_proto;
171 EXPECT_TRUE(ReadProtobufFromFile(&output_perf_data_proto, input_filename));
172
173 EXPECT_TRUE(DeserializeToFile(output_perf_data_proto, output));
174
175 EXPECT_TRUE(WriteProtobufToFile(output_perf_data_proto, output_filename));
176
177 EXPECT_NE(GetFileSize(input_filename), 0);
178 ASSERT_TRUE(CompareFileContents(input_filename, output_filename));
179
180 remove(input_filename.c_str());
181 remove(output_filename.c_str());
182 }
183
184 } // namespace
185
TEST_P(SerializePerfDataFiles,Test1Cycle)186 TEST_P(SerializePerfDataFiles, Test1Cycle) {
187 ScopedTempDir output_dir;
188 ASSERT_FALSE(output_dir.path().empty());
189 string output_path = output_dir.path();
190
191 // Read perf data using the PerfReader class.
192 // Dump it to a protobuf.
193 // Read the protobuf, and reconstruct the perf data.
194 PerfReader input_perf_reader, output_perf_reader, output_perf_reader1,
195 output_perf_reader2;
196 PerfDataProto perf_data_proto, perf_data_proto1;
197
198 const string test_file = GetParam();
199 const string input_perf_data = GetTestInputFilePath(test_file);
200 const string output_perf_data = output_path + test_file + ".serialized.out";
201 const string output_perf_data1 =
202 output_path + test_file + ".serialized.1.out";
203
204 LOG(INFO) << "Testing " << input_perf_data;
205 ASSERT_TRUE(input_perf_reader.ReadFile(input_perf_data));
206
207 // Discard unused events for a pseudorandom selection of half the test data
208 // files. The selection is based on the Md5sum prefix of the file contents,
209 // so that the files can be moved around in the |kPerfDataFiles| list or
210 // renamed.
211 std::vector<char> test_file_data;
212 ASSERT_TRUE(FileToBuffer(input_perf_data, &test_file_data));
213 bool discard = (Md5Prefix(test_file_data) % 2 == 0);
214
215 SerializeAndDeserialize(input_perf_data, output_perf_data, false, discard);
216 output_perf_reader.ReadFile(output_perf_data);
217 SerializeAndDeserialize(output_perf_data, output_perf_data1, false,
218 discard);
219 output_perf_reader1.ReadFile(output_perf_data1);
220
221 ASSERT_TRUE(CompareFileContents(output_perf_data, output_perf_data1));
222
223 string output_perf_data2 = output_path + test_file + ".io.out";
224 SerializeToFileAndBack(input_perf_data, output_perf_data2);
225 output_perf_reader2.ReadFile(output_perf_data2);
226
227 // Make sure the # of events do not increase. They can decrease because
228 // some unused non-sample events may be discarded.
229 if (discard) {
230 ASSERT_LE(output_perf_reader.events().size(),
231 input_perf_reader.events().size());
232 } else {
233 ASSERT_EQ(output_perf_reader.events().size(),
234 input_perf_reader.events().size());
235 }
236 ASSERT_EQ(output_perf_reader1.events().size(),
237 output_perf_reader.events().size());
238 ASSERT_EQ(output_perf_reader2.events().size(),
239 input_perf_reader.events().size());
240
241 EXPECT_TRUE(CheckPerfDataAgainstBaseline(output_perf_data));
242 EXPECT_TRUE(ComparePerfBuildIDLists(input_perf_data, output_perf_data));
243 EXPECT_TRUE(CheckPerfDataAgainstBaseline(output_perf_data2));
244 EXPECT_TRUE(ComparePerfBuildIDLists(output_perf_data, output_perf_data2));
245 }
246
TEST_P(SerializeAllPerfDataFiles,TestRemap)247 TEST_P(SerializeAllPerfDataFiles, TestRemap) {
248 ScopedTempDir output_dir;
249 ASSERT_FALSE(output_dir.path().empty());
250 const string output_path = output_dir.path();
251
252 // Read perf data using the PerfReader class with address remapping.
253 // Dump it to a protobuf.
254 // Read the protobuf, and reconstruct the perf data.
255 const string test_file = GetParam();
256 const string input_perf_data = GetTestInputFilePath(test_file);
257 LOG(INFO) << "Testing " << input_perf_data;
258 const string output_perf_data = output_path + test_file + ".ser.remap.out";
259 SerializeAndDeserialize(input_perf_data, output_perf_data, true, true);
260 }
261
TEST_P(SerializePerfDataFiles,TestCommMd5s)262 TEST_P(SerializePerfDataFiles, TestCommMd5s) {
263 ScopedTempDir output_dir;
264 ASSERT_FALSE(output_dir.path().empty());
265 string output_path = output_dir.path();
266
267 // Replace command strings with their Md5sums. Test size adjustment for
268 // command strings.
269 const string test_file = GetParam();
270 const string input_perf_data = GetTestInputFilePath(test_file);
271 LOG(INFO) << "Testing COMM Md5sum for " << input_perf_data;
272
273 PerfDataProto perf_data_proto;
274 EXPECT_TRUE(SerializeFromFile(input_perf_data, &perf_data_proto));
275
276 // Need to get file attrs to construct a SampleInfoReader within
277 // |serializer|.
278 ASSERT_GT(perf_data_proto.file_attrs().size(), 0U);
279 ASSERT_TRUE(perf_data_proto.file_attrs(0).has_attr());
280 PerfSerializer serializer;
281 PerfFileAttr attr;
282 const auto& proto_attr = perf_data_proto.file_attrs(0);
283 ASSERT_TRUE(serializer.DeserializePerfFileAttr(proto_attr, &attr));
284 serializer.CreateSampleInfoReader(attr, false /* read_cross_endian */);
285
286 for (int j = 0; j < perf_data_proto.events_size(); ++j) {
287 PerfDataProto_PerfEvent& event = *perf_data_proto.mutable_events(j);
288 if (event.header().type() != PERF_RECORD_COMM) continue;
289 CHECK(event.has_comm_event());
290
291 string comm_md5_string = UintToString(event.comm_event().comm_md5_prefix());
292 // Make sure it fits in the comm string array, accounting for the null
293 // terminator.
294 struct comm_event dummy;
295 if (comm_md5_string.size() > arraysize(dummy.comm) - 1)
296 comm_md5_string.resize(arraysize(dummy.comm) - 1);
297 int64_t string_len_diff =
298 GetUint64AlignedStringLength(comm_md5_string) -
299 GetUint64AlignedStringLength(event.comm_event().comm());
300 event.mutable_comm_event()->set_comm(comm_md5_string);
301
302 // Update with the new size.
303 event.mutable_header()->set_size(event.header().size() + string_len_diff);
304 }
305
306 const string output_perf_data = output_path + test_file + ".ser.comm.out";
307 EXPECT_TRUE(DeserializeToFile(perf_data_proto, output_perf_data));
308 EXPECT_TRUE(CheckPerfDataAgainstBaseline(output_perf_data));
309 }
310
TEST_P(SerializePerfDataFiles,TestMmapMd5s)311 TEST_P(SerializePerfDataFiles, TestMmapMd5s) {
312 ScopedTempDir output_dir;
313 ASSERT_FALSE(output_dir.path().empty());
314 string output_path = output_dir.path();
315
316 // Replace MMAP filename strings with their Md5sums. Test size adjustment for
317 // MMAP filename strings.
318 const string test_file = GetParam();
319 const string input_perf_data = GetTestInputFilePath(test_file);
320 LOG(INFO) << "Testing MMAP Md5sum for " << input_perf_data;
321
322 PerfDataProto perf_data_proto;
323 EXPECT_TRUE(SerializeFromFile(input_perf_data, &perf_data_proto));
324
325 // Need to get file attrs to construct a SampleInfoReader within
326 // |serializer|.
327 ASSERT_GT(perf_data_proto.file_attrs().size(), 0U);
328 ASSERT_TRUE(perf_data_proto.file_attrs(0).has_attr());
329 PerfSerializer serializer;
330 PerfFileAttr attr;
331 const auto& proto_attr = perf_data_proto.file_attrs(0);
332 ASSERT_TRUE(serializer.DeserializePerfFileAttr(proto_attr, &attr));
333 serializer.CreateSampleInfoReader(attr, false /* read_cross_endian */);
334
335 for (int j = 0; j < perf_data_proto.events_size(); ++j) {
336 PerfDataProto_PerfEvent& event = *perf_data_proto.mutable_events(j);
337 if (event.header().type() != PERF_RECORD_MMAP) continue;
338 ASSERT_TRUE(event.has_mmap_event());
339
340 string filename_md5_string =
341 UintToString(event.mmap_event().filename_md5_prefix());
342 struct mmap_event dummy;
343 // Make sure the Md5 prefix string can fit in the filename buffer,
344 // including the null terminator
345 if (filename_md5_string.size() > arraysize(dummy.filename) - 1)
346 filename_md5_string.resize(arraysize(dummy.filename) - 1);
347
348 int64_t string_len_diff =
349 GetUint64AlignedStringLength(filename_md5_string) -
350 GetUint64AlignedStringLength(event.mmap_event().filename());
351 event.mutable_mmap_event()->set_filename(filename_md5_string);
352
353 // Update with the new size.
354 event.mutable_header()->set_size(event.header().size() + string_len_diff);
355 }
356
357 const string output_perf_data = output_path + test_file + ".ser.mmap.out";
358 // Make sure the data can be deserialized after replacing the filenames with
359 // Md5sum prefixes. No need to check the output.
360 EXPECT_TRUE(DeserializeToFile(perf_data_proto, output_perf_data));
361 }
362
TEST_P(SerializePerfDataProtoFiles,TestProtoFiles)363 TEST_P(SerializePerfDataProtoFiles, TestProtoFiles) {
364 const string test_file = GetParam();
365 string perf_data_proto_file = GetTestInputFilePath(test_file);
366 LOG(INFO) << "Testing " << perf_data_proto_file;
367 std::vector<char> data;
368 ASSERT_TRUE(FileToBuffer(perf_data_proto_file, &data));
369 string text(data.begin(), data.end());
370
371 PerfDataProto perf_data_proto;
372 ASSERT_TRUE(TextFormat::ParseFromString(text, &perf_data_proto));
373
374 // Test deserializing.
375 PerfReader deserializer;
376 EXPECT_TRUE(deserializer.Deserialize(perf_data_proto));
377 }
378
TEST_P(SerializePerfDataFiles,TestBuildIDs)379 TEST_P(SerializePerfDataFiles, TestBuildIDs) {
380 const string test_file = GetParam();
381 string perf_data_file = GetTestInputFilePath(test_file);
382 LOG(INFO) << "Testing " << perf_data_file;
383
384 // Serialize into a protobuf.
385 PerfDataProto perf_data_proto;
386 EXPECT_TRUE(SerializeFromFile(perf_data_file, &perf_data_proto));
387
388 // Test a file with build ID filenames removed.
389 for (int i = 0; i < perf_data_proto.build_ids_size(); ++i) {
390 perf_data_proto.mutable_build_ids(i)->clear_filename();
391 }
392 PerfReader deserializer;
393 EXPECT_TRUE(deserializer.Deserialize(perf_data_proto));
394 }
395
TEST(PerfSerializerTest,SerializesAndDeserializesTraceMetadata)396 TEST(PerfSerializerTest, SerializesAndDeserializesTraceMetadata) {
397 std::stringstream input;
398
399 const size_t data_size =
400 testing::ExamplePerfSampleEvent_Tracepoint::kEventSize;
401
402 // header
403 testing::ExamplePerfDataFileHeader file_header(1 << HEADER_TRACING_DATA);
404 file_header.WithAttrCount(1).WithDataSize(data_size);
405 file_header.WriteTo(&input);
406 const perf_file_header& header = file_header.header();
407 // attrs
408 testing::ExamplePerfFileAttr_Tracepoint(73).WriteTo(&input);
409 // data
410 ASSERT_EQ(static_cast<u64>(input.tellp()), header.data.offset);
411 testing::ExamplePerfSampleEvent_Tracepoint().WriteTo(&input);
412 ASSERT_EQ(input.tellp(), file_header.data_end());
413 // metadata
414 const unsigned int metadata_count = 1;
415 // HEADER_TRACING_DATA
416 testing::ExampleTracingMetadata tracing_metadata(
417 file_header.data_end() + metadata_count * sizeof(perf_file_section));
418 tracing_metadata.index_entry().WriteTo(&input);
419 tracing_metadata.data().WriteTo(&input);
420
421 // Parse and Serialize
422
423 PerfReader reader;
424 ASSERT_TRUE(reader.ReadFromString(input.str()));
425
426 PerfDataProto perf_data_proto;
427 ASSERT_TRUE(reader.Serialize(&perf_data_proto));
428
429 const string& tracing_metadata_str = tracing_metadata.data().value();
430 const auto& tracing_data = perf_data_proto.tracing_data();
431 EXPECT_EQ(tracing_metadata_str, tracing_data.tracing_data());
432 EXPECT_EQ(Md5Prefix(tracing_metadata_str),
433 tracing_data.tracing_data_md5_prefix());
434
435 // Deserialize
436
437 PerfReader deserializer;
438 EXPECT_TRUE(deserializer.Deserialize(perf_data_proto));
439 EXPECT_EQ(tracing_metadata_str, deserializer.tracing_data());
440 }
441
TEST(PerfSerializerTest,SerializesAndDeserializesMmapEvents)442 TEST(PerfSerializerTest, SerializesAndDeserializesMmapEvents) {
443 std::stringstream input;
444
445 // header
446 testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
447
448 // data
449
450 // PERF_RECORD_HEADER_ATTR
451 testing::ExamplePerfEventAttrEvent_Hardware(PERF_SAMPLE_IP | PERF_SAMPLE_TID,
452 true /*sample_id_all*/)
453 .WriteTo(&input);
454
455 // PERF_RECORD_MMAP
456 testing::ExampleMmapEvent(1001, 0x1c1000, 0x1000, 0, "/usr/lib/foo.so",
457 testing::SampleInfo().Tid(1001))
458 .WriteTo(&input);
459
460 // PERF_RECORD_MMAP2
461 testing::ExampleMmap2Event(1002, 0x2c1000, 0x2000, 0x3000, "/usr/lib/bar.so",
462 testing::SampleInfo().Tid(1002))
463 .WriteTo(&input);
464
465 // Parse and Serialize
466
467 PerfReader reader;
468 ASSERT_TRUE(reader.ReadFromString(input.str()));
469
470 PerfDataProto perf_data_proto;
471 ASSERT_TRUE(reader.Serialize(&perf_data_proto));
472
473 EXPECT_EQ(2, perf_data_proto.events().size());
474
475 {
476 const PerfDataProto::PerfEvent& event = perf_data_proto.events(0);
477 EXPECT_EQ(PERF_RECORD_MMAP, event.header().type());
478 EXPECT_TRUE(event.has_mmap_event());
479 const PerfDataProto::MMapEvent& mmap = event.mmap_event();
480 EXPECT_EQ(1001, mmap.pid());
481 EXPECT_EQ(1001, mmap.tid());
482 EXPECT_EQ(0x1c1000, mmap.start());
483 EXPECT_EQ(0x1000, mmap.len());
484 EXPECT_EQ(0, mmap.pgoff());
485 EXPECT_EQ("/usr/lib/foo.so", mmap.filename());
486 }
487
488 {
489 const PerfDataProto::PerfEvent& event = perf_data_proto.events(1);
490 EXPECT_EQ(PERF_RECORD_MMAP2, event.header().type());
491 EXPECT_TRUE(event.has_mmap_event());
492 const PerfDataProto::MMapEvent& mmap = event.mmap_event();
493 EXPECT_EQ(1002, mmap.pid());
494 EXPECT_EQ(1002, mmap.tid());
495 EXPECT_EQ(0x2c1000, mmap.start());
496 EXPECT_EQ(0x2000, mmap.len());
497 EXPECT_EQ(0x3000, mmap.pgoff());
498 EXPECT_EQ("/usr/lib/bar.so", mmap.filename());
499 // These values are hard-coded in ExampleMmap2Event:
500 EXPECT_EQ(6, mmap.maj());
501 EXPECT_EQ(7, mmap.min());
502 EXPECT_EQ(8, mmap.ino());
503 EXPECT_EQ(9, mmap.ino_generation());
504 EXPECT_EQ(1 | 2, mmap.prot());
505 EXPECT_EQ(2, mmap.flags());
506 }
507 }
508
TEST(PerfSerializerTest,SerializesAndDeserializesAuxtraceEvents)509 TEST(PerfSerializerTest, SerializesAndDeserializesAuxtraceEvents) {
510 std::stringstream input;
511
512 // header
513 testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
514
515 // data
516
517 // PERF_RECORD_HEADER_ATTR
518 testing::ExamplePerfEventAttrEvent_Hardware(PERF_SAMPLE_IP,
519 true /*sample_id_all*/)
520 .WriteTo(&input);
521
522 // PERF_RECORD_MMAP
523 testing::ExampleAuxtraceEvent(9, 0x2000, 7, 3, 0x68d, 4, 0, "/dev/zero")
524 .WriteTo(&input);
525
526 // Parse and Serialize
527
528 PerfReader reader;
529 ASSERT_TRUE(reader.ReadFromString(input.str()));
530
531 PerfDataProto perf_data_proto;
532 ASSERT_TRUE(reader.Serialize(&perf_data_proto));
533
534 EXPECT_EQ(1, perf_data_proto.events().size());
535
536 {
537 const PerfDataProto::PerfEvent& event = perf_data_proto.events(0);
538 EXPECT_EQ(PERF_RECORD_AUXTRACE, event.header().type());
539 EXPECT_TRUE(event.has_auxtrace_event());
540 const PerfDataProto::AuxtraceEvent& auxtrace_event = event.auxtrace_event();
541 EXPECT_EQ(9, auxtrace_event.size());
542 EXPECT_EQ(0x2000, auxtrace_event.offset());
543 EXPECT_EQ(7, auxtrace_event.reference());
544 EXPECT_EQ(3, auxtrace_event.idx());
545 EXPECT_EQ(0x68d, auxtrace_event.tid());
546 EXPECT_EQ("/dev/zero", auxtrace_event.trace_data());
547 }
548 }
549
550 // Regression test for http://crbug.com/501004.
TEST(PerfSerializerTest,SerializesAndDeserializesBuildIDs)551 TEST(PerfSerializerTest, SerializesAndDeserializesBuildIDs) {
552 std::stringstream input;
553
554 // header
555 testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
556
557 // no data
558
559 // PERF_RECORD_HEADER_ATTR
560 testing::ExamplePerfEventAttrEvent_Hardware(
561 PERF_SAMPLE_TID | PERF_SAMPLE_TIME, true /*sample_id_all*/)
562 .WriteTo(&input);
563
564 PerfReader reader;
565 ASSERT_TRUE(reader.ReadFromString(input.str()));
566
567 std::map<string, string> build_id_map;
568 build_id_map["file1"] = "0123456789abcdef0123456789abcdef01234567";
569 build_id_map["file2"] = "0123456789abcdef0123456789abcdef01230000";
570 build_id_map["file3"] = "0123456789abcdef0123456789abcdef00000000";
571 build_id_map["file4"] = "0123456789abcdef0123456789abcdef0000";
572 build_id_map["file5"] = "0123456789abcdef0123456789abcdef";
573 build_id_map["file6"] = "0123456789abcdef0123456789ab0000";
574 build_id_map["file7"] = "0123456789abcdef012345670000";
575 build_id_map["file8"] = "0123456789abcdef01234567";
576 build_id_map["file9"] = "00000000";
577 reader.InjectBuildIDs(build_id_map);
578
579 PerfDataProto perf_data_proto;
580 ASSERT_TRUE(reader.Serialize(&perf_data_proto));
581
582 // Verify that the build ID info was properly injected.
583 EXPECT_EQ(9, perf_data_proto.build_ids_size());
584 for (int i = 0; i < perf_data_proto.build_ids_size(); ++i) {
585 EXPECT_TRUE(perf_data_proto.build_ids(i).has_filename());
586 EXPECT_TRUE(perf_data_proto.build_ids(i).has_build_id_hash());
587 }
588
589 // Verify that the serialized build IDs have had their trailing zeroes
590 // trimmed.
591 EXPECT_EQ("file1", perf_data_proto.build_ids(0).filename());
592 EXPECT_EQ("0123456789abcdef0123456789abcdef01234567",
593 RawDataToHexString(perf_data_proto.build_ids(0).build_id_hash()));
594
595 EXPECT_EQ("file2", perf_data_proto.build_ids(1).filename());
596 EXPECT_EQ("0123456789abcdef0123456789abcdef01230000",
597 RawDataToHexString(perf_data_proto.build_ids(1).build_id_hash()));
598
599 EXPECT_EQ("file3", perf_data_proto.build_ids(2).filename());
600 EXPECT_EQ("0123456789abcdef0123456789abcdef",
601 RawDataToHexString(perf_data_proto.build_ids(2).build_id_hash()));
602
603 EXPECT_EQ("file4", perf_data_proto.build_ids(3).filename());
604 EXPECT_EQ("0123456789abcdef0123456789abcdef",
605 RawDataToHexString(perf_data_proto.build_ids(3).build_id_hash()));
606
607 EXPECT_EQ("file5", perf_data_proto.build_ids(4).filename());
608 EXPECT_EQ("0123456789abcdef0123456789abcdef",
609 RawDataToHexString(perf_data_proto.build_ids(4).build_id_hash()));
610
611 EXPECT_EQ("file6", perf_data_proto.build_ids(5).filename());
612 EXPECT_EQ("0123456789abcdef0123456789ab0000",
613 RawDataToHexString(perf_data_proto.build_ids(5).build_id_hash()));
614
615 EXPECT_EQ("file7", perf_data_proto.build_ids(6).filename());
616 EXPECT_EQ("0123456789abcdef01234567",
617 RawDataToHexString(perf_data_proto.build_ids(6).build_id_hash()));
618
619 EXPECT_EQ("file8", perf_data_proto.build_ids(7).filename());
620 EXPECT_EQ("0123456789abcdef01234567",
621 RawDataToHexString(perf_data_proto.build_ids(7).build_id_hash()));
622
623 EXPECT_EQ("file9", perf_data_proto.build_ids(8).filename());
624 EXPECT_EQ("",
625 RawDataToHexString(perf_data_proto.build_ids(8).build_id_hash()));
626
627 // Check deserialization.
628 PerfReader out_reader;
629 EXPECT_TRUE(out_reader.Deserialize(perf_data_proto));
630 const auto& build_ids = out_reader.build_ids();
631 ASSERT_EQ(9, build_ids.size());
632
633 std::vector<malloced_unique_ptr<build_id_event>> raw_build_ids(
634 build_ids.size());
635
636 // Convert the build IDs back to raw build ID events.
637 PerfSerializer serializer;
638 for (int i = 0; i < build_ids.size(); ++i) {
639 ASSERT_TRUE(serializer.DeserializeBuildIDEvent(build_ids.Get(i),
640 &raw_build_ids[i]));
641 }
642
643 // All trimmed build IDs should be padded to the full 20 byte length.
644 EXPECT_EQ(string("file1"), raw_build_ids[0]->filename);
645 EXPECT_EQ("0123456789abcdef0123456789abcdef01234567",
646 RawDataToHexString(raw_build_ids[0]->build_id, kBuildIDArraySize));
647
648 EXPECT_EQ(string("file2"), raw_build_ids[1]->filename);
649 EXPECT_EQ("0123456789abcdef0123456789abcdef01230000",
650 RawDataToHexString(raw_build_ids[1]->build_id, kBuildIDArraySize));
651
652 EXPECT_EQ(string("file3"), raw_build_ids[2]->filename);
653 EXPECT_EQ("0123456789abcdef0123456789abcdef00000000",
654 RawDataToHexString(raw_build_ids[2]->build_id, kBuildIDArraySize));
655
656 EXPECT_EQ(string("file4"), raw_build_ids[3]->filename);
657 EXPECT_EQ("0123456789abcdef0123456789abcdef00000000",
658 RawDataToHexString(raw_build_ids[3]->build_id, kBuildIDArraySize));
659
660 EXPECT_EQ(string("file5"), raw_build_ids[4]->filename);
661 EXPECT_EQ("0123456789abcdef0123456789abcdef00000000",
662 RawDataToHexString(raw_build_ids[4]->build_id, kBuildIDArraySize));
663
664 EXPECT_EQ(string("file6"), raw_build_ids[5]->filename);
665 EXPECT_EQ("0123456789abcdef0123456789ab000000000000",
666 RawDataToHexString(raw_build_ids[5]->build_id, kBuildIDArraySize));
667
668 EXPECT_EQ(string("file7"), raw_build_ids[6]->filename);
669 EXPECT_EQ("0123456789abcdef012345670000000000000000",
670 RawDataToHexString(raw_build_ids[6]->build_id, kBuildIDArraySize));
671
672 EXPECT_EQ(string("file8"), raw_build_ids[7]->filename);
673 EXPECT_EQ("0123456789abcdef012345670000000000000000",
674 RawDataToHexString(raw_build_ids[7]->build_id, kBuildIDArraySize));
675
676 EXPECT_EQ(string("file9"), raw_build_ids[8]->filename);
677 EXPECT_EQ("0000000000000000000000000000000000000000",
678 RawDataToHexString(raw_build_ids[8]->build_id, kBuildIDArraySize));
679 }
680
681 // Regression test for http://crbug.com/500746.
TEST(PerfSerializerTest,SerializesAndDeserializesForkAndExitEvents)682 TEST(PerfSerializerTest, SerializesAndDeserializesForkAndExitEvents) {
683 std::stringstream input;
684
685 // header
686 testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
687
688 // data
689
690 // PERF_RECORD_HEADER_ATTR
691 testing::ExamplePerfEventAttrEvent_Hardware(
692 PERF_SAMPLE_TID | PERF_SAMPLE_TIME, true /*sample_id_all*/)
693 .WriteTo(&input);
694
695 // PERF_RECORD_FORK
696 testing::ExampleForkEvent(
697 1010, 1020, 1030, 1040, 355ULL * 1000000000,
698 testing::SampleInfo().Tid(2010, 2020).Time(356ULL * 1000000000))
699 .WriteTo(&input);
700
701 // PERF_RECORD_EXIT
702 testing::ExampleExitEvent(
703 3010, 3020, 3030, 3040, 432ULL * 1000000000,
704 testing::SampleInfo().Tid(4010, 4020).Time(433ULL * 1000000000))
705 .WriteTo(&input);
706
707 // Parse and serialize.
708 PerfReader reader;
709 ASSERT_TRUE(reader.ReadFromString(input.str()));
710
711 PerfDataProto perf_data_proto;
712 ASSERT_TRUE(reader.Serialize(&perf_data_proto));
713
714 ASSERT_EQ(2, perf_data_proto.events_size());
715
716 {
717 const PerfDataProto_PerfEvent& event = perf_data_proto.events(0);
718 EXPECT_EQ(PERF_RECORD_FORK, event.header().type());
719 EXPECT_TRUE(event.has_fork_event());
720 EXPECT_FALSE(event.has_exit_event());
721
722 EXPECT_EQ(1010, event.fork_event().pid());
723 EXPECT_EQ(1020, event.fork_event().ppid());
724 EXPECT_EQ(1030, event.fork_event().tid());
725 EXPECT_EQ(1040, event.fork_event().ptid());
726 EXPECT_EQ(355ULL * 1000000000, event.fork_event().fork_time_ns());
727
728 EXPECT_EQ(2010, event.fork_event().sample_info().pid());
729 EXPECT_EQ(2020, event.fork_event().sample_info().tid());
730 EXPECT_EQ(356ULL * 1000000000,
731 event.fork_event().sample_info().sample_time_ns());
732 }
733
734 {
735 const PerfDataProto_PerfEvent& event = perf_data_proto.events(1);
736 EXPECT_EQ(PERF_RECORD_EXIT, event.header().type());
737 EXPECT_FALSE(event.has_fork_event());
738 EXPECT_TRUE(event.has_exit_event());
739
740 EXPECT_EQ(3010, event.exit_event().pid());
741 EXPECT_EQ(3020, event.exit_event().ppid());
742 EXPECT_EQ(3030, event.exit_event().tid());
743 EXPECT_EQ(3040, event.exit_event().ptid());
744 EXPECT_EQ(432ULL * 1000000000, event.exit_event().fork_time_ns());
745
746 EXPECT_EQ(4010, event.exit_event().sample_info().pid());
747 EXPECT_EQ(4020, event.exit_event().sample_info().tid());
748 EXPECT_EQ(433ULL * 1000000000,
749 event.exit_event().sample_info().sample_time_ns());
750 }
751
752 // Deserialize and verify events.
753 PerfReader out_reader;
754 ASSERT_TRUE(out_reader.Deserialize(perf_data_proto));
755
756 EXPECT_EQ(2, out_reader.events().size());
757
758 {
759 const PerfEvent& event = out_reader.events().Get(0);
760 EXPECT_EQ(PERF_RECORD_FORK, event.header().type());
761
762 EXPECT_EQ(1010, event.fork_event().pid());
763 EXPECT_EQ(1020, event.fork_event().ppid());
764 EXPECT_EQ(1030, event.fork_event().tid());
765 EXPECT_EQ(1040, event.fork_event().ptid());
766 EXPECT_EQ(355ULL * 1000000000, event.fork_event().fork_time_ns());
767
768 const SampleInfo& sample_info = event.fork_event().sample_info();
769 EXPECT_EQ(2010, sample_info.pid());
770 EXPECT_EQ(2020, sample_info.tid());
771 EXPECT_EQ(356ULL * 1000000000, sample_info.sample_time_ns());
772 }
773
774 {
775 const PerfEvent& event = out_reader.events().Get(1);
776 EXPECT_EQ(PERF_RECORD_EXIT, event.header().type());
777
778 EXPECT_EQ(3010, event.exit_event().pid());
779 EXPECT_EQ(3020, event.exit_event().ppid());
780 EXPECT_EQ(3030, event.exit_event().tid());
781 EXPECT_EQ(3040, event.exit_event().ptid());
782 EXPECT_EQ(432ULL * 1000000000, event.exit_event().fork_time_ns());
783
784 const SampleInfo& sample_info = event.exit_event().sample_info();
785 EXPECT_EQ(4010, sample_info.pid());
786 EXPECT_EQ(4020, sample_info.tid());
787 EXPECT_EQ(433ULL * 1000000000, sample_info.sample_time_ns());
788 }
789 }
790
791 // Regression test for http://crbug.com/500746.
TEST(PerfSerializerTest,DeserializeLegacyExitEvents)792 TEST(PerfSerializerTest, DeserializeLegacyExitEvents) {
793 std::stringstream input;
794
795 // header
796 testing::ExamplePipedPerfDataFileHeader().WriteTo(&input);
797
798 // data
799
800 // PERF_RECORD_HEADER_ATTR
801 testing::ExamplePerfEventAttrEvent_Hardware(
802 PERF_SAMPLE_TID | PERF_SAMPLE_TIME, true /*sample_id_all*/)
803 .WriteTo(&input);
804
805 // PERF_RECORD_EXIT
806 testing::ExampleExitEvent(
807 3010, 3020, 3030, 3040, 432ULL * 1000000000,
808 testing::SampleInfo().Tid(4010, 4020).Time(433ULL * 1000000000))
809 .WriteTo(&input);
810
811 // Parse and serialize.
812 PerfReader reader;
813 ASSERT_TRUE(reader.ReadFromString(input.str()));
814
815 PerfDataProto proto;
816 ASSERT_TRUE(reader.Serialize(&proto));
817
818 ASSERT_EQ(1, proto.events_size());
819 ASSERT_TRUE(proto.events(0).has_exit_event());
820 ASSERT_FALSE(proto.events(0).has_fork_event());
821
822 // Modify the protobuf to store the exit event in the |fork_event| field
823 // instead.
824 PerfDataProto_ForkEvent ex;
825 ex.CopyFrom(proto.events(0).exit_event());
826 proto.mutable_events(0)->clear_exit_event();
827 proto.mutable_events(0)->mutable_fork_event()->CopyFrom(ex);
828
829 PerfReader out_reader;
830 ASSERT_TRUE(out_reader.Deserialize(proto));
831
832 EXPECT_EQ(1U, out_reader.events().size());
833
834 const PerfEvent& event = out_reader.events().Get(0);
835 EXPECT_EQ(PERF_RECORD_EXIT, event.header().type());
836 EXPECT_EQ(3010, event.fork_event().pid());
837 EXPECT_EQ(3020, event.fork_event().ppid());
838 EXPECT_EQ(3030, event.fork_event().tid());
839 EXPECT_EQ(3040, event.fork_event().ptid());
840 EXPECT_EQ(432ULL * 1000000000, event.fork_event().fork_time_ns());
841
842 const SampleInfo& sample_info = event.fork_event().sample_info();
843 EXPECT_EQ(4010, sample_info.pid());
844 EXPECT_EQ(4020, sample_info.tid());
845 EXPECT_EQ(433ULL * 1000000000, sample_info.sample_time_ns());
846 }
847
848 namespace {
AllPerfData()849 std::vector<const char*> AllPerfData() {
850 const auto& files = perf_test_files::GetPerfDataFiles();
851 const auto& piped = perf_test_files::GetPerfPipedDataFiles();
852
853 std::vector<const char*> ret(std::begin(files), std::end(files));
854 ret.insert(std::end(ret), std::begin(piped), std::end(piped));
855 return ret;
856 }
857 } // namespace
858
859 INSTANTIATE_TEST_CASE_P(
860 PerfSerializerTest, SerializePerfDataFiles,
861 ::testing::ValuesIn(perf_test_files::GetPerfDataFiles()));
862 INSTANTIATE_TEST_CASE_P(PerfSerializerTest, SerializeAllPerfDataFiles,
863 ::testing::ValuesIn(AllPerfData()));
864 INSTANTIATE_TEST_CASE_P(
865 PerfSerializerTest, SerializePerfDataProtoFiles,
866 ::testing::ValuesIn(perf_test_files::GetPerfDataProtoFiles()));
867 } // namespace quipper
868