Home | History | Annotate | Download | only in quipper
      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|.
     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.
     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.
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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.
    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.
    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.
    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 {
    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