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