• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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