1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "record_file.h" 18 19 #include <fcntl.h> 20 #include <string.h> 21 #include <set> 22 #include <vector> 23 24 #include <android-base/logging.h> 25 26 #include "event_attr.h" 27 #include "record.h" 28 #include "utils.h" 29 30 using namespace PerfFileFormat; 31 32 namespace PerfFileFormat { 33 34 static const std::map<int, std::string> feature_name_map = { 35 {FEAT_TRACING_DATA, "tracing_data"}, 36 {FEAT_BUILD_ID, "build_id"}, 37 {FEAT_HOSTNAME, "hostname"}, 38 {FEAT_OSRELEASE, "osrelease"}, 39 {FEAT_VERSION, "version"}, 40 {FEAT_ARCH, "arch"}, 41 {FEAT_NRCPUS, "nrcpus"}, 42 {FEAT_CPUDESC, "cpudesc"}, 43 {FEAT_CPUID, "cpuid"}, 44 {FEAT_TOTAL_MEM, "total_mem"}, 45 {FEAT_CMDLINE, "cmdline"}, 46 {FEAT_EVENT_DESC, "event_desc"}, 47 {FEAT_CPU_TOPOLOGY, "cpu_topology"}, 48 {FEAT_NUMA_TOPOLOGY, "numa_topology"}, 49 {FEAT_BRANCH_STACK, "branch_stack"}, 50 {FEAT_PMU_MAPPINGS, "pmu_mappings"}, 51 {FEAT_GROUP_DESC, "group_desc"}, 52 {FEAT_AUXTRACE, "auxtrace"}, 53 {FEAT_FILE, "file"}, 54 {FEAT_META_INFO, "meta_info"}, 55 }; 56 57 std::string GetFeatureName(int feature_id) { 58 auto it = feature_name_map.find(feature_id); 59 return it == feature_name_map.end() ? "" : it->second; 60 } 61 62 int GetFeatureId(const std::string& feature_name) { 63 for (auto& pair : feature_name_map) { 64 if (pair.second == feature_name) { 65 return pair.first; 66 } 67 } 68 return -1; 69 } 70 71 } // namespace PerfFileFormat 72 73 std::unique_ptr<RecordFileReader> RecordFileReader::CreateInstance(const std::string& filename) { 74 std::string mode = std::string("rb") + CLOSE_ON_EXEC_MODE; 75 FILE* fp = fopen(filename.c_str(), mode.c_str()); 76 if (fp == nullptr) { 77 PLOG(ERROR) << "failed to open record file '" << filename << "'"; 78 return nullptr; 79 } 80 auto reader = std::unique_ptr<RecordFileReader>(new RecordFileReader(filename, fp)); 81 if (!reader->ReadHeader() || !reader->ReadAttrSection() || 82 !reader->ReadFeatureSectionDescriptors() || !reader->ReadMetaInfoFeature()) { 83 return nullptr; 84 } 85 reader->UseRecordingEnvironment(); 86 return reader; 87 } 88 89 RecordFileReader::RecordFileReader(const std::string& filename, FILE* fp) 90 : filename_(filename), record_fp_(fp), event_id_pos_in_sample_records_(0), 91 event_id_reverse_pos_in_non_sample_records_(0), read_record_size_(0) { 92 } 93 94 RecordFileReader::~RecordFileReader() { 95 if (record_fp_ != nullptr) { 96 Close(); 97 } 98 } 99 100 bool RecordFileReader::Close() { 101 bool result = true; 102 if (fclose(record_fp_) != 0) { 103 PLOG(ERROR) << "failed to close record file '" << filename_ << "'"; 104 result = false; 105 } 106 record_fp_ = nullptr; 107 return result; 108 } 109 110 bool RecordFileReader::ReadHeader() { 111 if (!Read(&header_, sizeof(header_))) { 112 return false; 113 } 114 if (memcmp(header_.magic, PERF_MAGIC, sizeof(header_.magic)) != 0) { 115 LOG(ERROR) << filename_ << " is not a valid profiling record file."; 116 return false; 117 } 118 return true; 119 } 120 121 bool RecordFileReader::ReadAttrSection() { 122 size_t attr_count = header_.attrs.size / header_.attr_size; 123 if (header_.attr_size != sizeof(FileAttr)) { 124 LOG(DEBUG) << "attr size (" << header_.attr_size << ") in " << filename_ 125 << " doesn't match expected size (" << sizeof(FileAttr) << ")"; 126 } 127 if (attr_count == 0) { 128 LOG(ERROR) << "no attr in file " << filename_; 129 return false; 130 } 131 if (fseek(record_fp_, header_.attrs.offset, SEEK_SET) != 0) { 132 PLOG(ERROR) << "fseek() failed"; 133 return false; 134 } 135 for (size_t i = 0; i < attr_count; ++i) { 136 std::vector<char> buf(header_.attr_size); 137 if (!Read(buf.data(), buf.size())) { 138 return false; 139 } 140 // The size of perf_event_attr is changing between different linux kernel versions. 141 // Make sure we copy correct data to memory. 142 FileAttr attr; 143 memset(&attr, 0, sizeof(attr)); 144 size_t section_desc_size = sizeof(attr.ids); 145 size_t perf_event_attr_size = header_.attr_size - section_desc_size; 146 memcpy(&attr.attr, &buf[0], std::min(sizeof(attr.attr), perf_event_attr_size)); 147 memcpy(&attr.ids, &buf[perf_event_attr_size], section_desc_size); 148 file_attrs_.push_back(attr); 149 } 150 if (file_attrs_.size() > 1) { 151 std::vector<perf_event_attr> attrs; 152 for (const auto& file_attr : file_attrs_) { 153 attrs.push_back(file_attr.attr); 154 } 155 if (!GetCommonEventIdPositionsForAttrs(attrs, &event_id_pos_in_sample_records_, 156 &event_id_reverse_pos_in_non_sample_records_)) { 157 return false; 158 } 159 } 160 for (size_t i = 0; i < file_attrs_.size(); ++i) { 161 std::vector<uint64_t> ids; 162 if (!ReadIdsForAttr(file_attrs_[i], &ids)) { 163 return false; 164 } 165 event_ids_for_file_attrs_.push_back(ids); 166 for (auto id : ids) { 167 event_id_to_attr_map_[id] = i; 168 } 169 } 170 return true; 171 } 172 173 bool RecordFileReader::ReadFeatureSectionDescriptors() { 174 std::vector<int> features; 175 for (size_t i = 0; i < sizeof(header_.features); ++i) { 176 for (size_t j = 0; j < 8; ++j) { 177 if (header_.features[i] & (1 << j)) { 178 features.push_back(i * 8 + j); 179 } 180 } 181 } 182 uint64_t feature_section_offset = header_.data.offset + header_.data.size; 183 if (fseek(record_fp_, feature_section_offset, SEEK_SET) != 0) { 184 PLOG(ERROR) << "fseek() failed"; 185 return false; 186 } 187 for (const auto& id : features) { 188 SectionDesc desc; 189 if (!Read(&desc, sizeof(desc))) { 190 return false; 191 } 192 feature_section_descriptors_.emplace(id, desc); 193 } 194 return true; 195 } 196 197 bool RecordFileReader::ReadIdsForAttr(const FileAttr& attr, std::vector<uint64_t>* ids) { 198 size_t id_count = attr.ids.size / sizeof(uint64_t); 199 if (fseek(record_fp_, attr.ids.offset, SEEK_SET) != 0) { 200 PLOG(ERROR) << "fseek() failed"; 201 return false; 202 } 203 ids->resize(id_count); 204 if (!Read(ids->data(), attr.ids.size)) { 205 return false; 206 } 207 return true; 208 } 209 210 void RecordFileReader::UseRecordingEnvironment() { 211 std::string arch = ReadFeatureString(FEAT_ARCH); 212 if (!arch.empty()) { 213 scoped_arch_.reset(new ScopedCurrentArch(GetArchType(arch))); 214 } 215 auto& meta_info = GetMetaInfoFeature(); 216 if (auto it = meta_info.find("event_type_info"); it != meta_info.end()) { 217 scoped_event_types_.reset(new ScopedEventTypes(it->second)); 218 } 219 } 220 221 bool RecordFileReader::ReadDataSection( 222 const std::function<bool(std::unique_ptr<Record>)>& callback) { 223 std::unique_ptr<Record> record; 224 while (ReadRecord(record)) { 225 if (record == nullptr) { 226 return true; 227 } 228 if (!callback(std::move(record))) { 229 return false; 230 } 231 } 232 return false; 233 } 234 235 bool RecordFileReader::ReadRecord(std::unique_ptr<Record>& record) { 236 if (read_record_size_ == 0) { 237 if (fseek(record_fp_, header_.data.offset, SEEK_SET) != 0) { 238 PLOG(ERROR) << "fseek() failed"; 239 return false; 240 } 241 } 242 record = nullptr; 243 if (read_record_size_ < header_.data.size) { 244 record = ReadRecord(); 245 if (record == nullptr) { 246 return false; 247 } 248 if (record->type() == SIMPLE_PERF_RECORD_EVENT_ID) { 249 ProcessEventIdRecord(*static_cast<EventIdRecord*>(record.get())); 250 } 251 } 252 return true; 253 } 254 255 std::unique_ptr<Record> RecordFileReader::ReadRecord() { 256 char header_buf[Record::header_size()]; 257 if (!Read(header_buf, Record::header_size())) { 258 return nullptr; 259 } 260 RecordHeader header(header_buf); 261 std::unique_ptr<char[]> p; 262 if (header.type == SIMPLE_PERF_RECORD_SPLIT) { 263 // Read until meeting a RECORD_SPLIT_END record. 264 std::vector<char> buf; 265 size_t cur_size = 0; 266 char header_buf[Record::header_size()]; 267 while (header.type == SIMPLE_PERF_RECORD_SPLIT) { 268 size_t bytes_to_read = header.size - Record::header_size(); 269 buf.resize(cur_size + bytes_to_read); 270 if (!Read(&buf[cur_size], bytes_to_read)) { 271 return nullptr; 272 } 273 cur_size += bytes_to_read; 274 read_record_size_ += header.size; 275 if (!Read(header_buf, Record::header_size())) { 276 return nullptr; 277 } 278 header = RecordHeader(header_buf); 279 } 280 if (header.type != SIMPLE_PERF_RECORD_SPLIT_END) { 281 LOG(ERROR) << "SPLIT records are not followed by a SPLIT_END record."; 282 return nullptr; 283 } 284 read_record_size_ += header.size; 285 header = RecordHeader(buf.data()); 286 p.reset(new char[header.size]); 287 memcpy(p.get(), buf.data(), buf.size()); 288 } else { 289 p.reset(new char[header.size]); 290 memcpy(p.get(), header_buf, Record::header_size()); 291 if (header.size > Record::header_size()) { 292 if (!Read(p.get() + Record::header_size(), header.size - Record::header_size())) { 293 return nullptr; 294 } 295 } 296 read_record_size_ += header.size; 297 } 298 299 const perf_event_attr* attr = &file_attrs_[0].attr; 300 if (file_attrs_.size() > 1 && header.type < PERF_RECORD_USER_DEFINED_TYPE_START) { 301 bool has_event_id = false; 302 uint64_t event_id; 303 if (header.type == PERF_RECORD_SAMPLE) { 304 if (header.size > event_id_pos_in_sample_records_ + sizeof(uint64_t)) { 305 has_event_id = true; 306 event_id = *reinterpret_cast<uint64_t*>(p.get() + event_id_pos_in_sample_records_); 307 } 308 } else { 309 if (header.size > event_id_reverse_pos_in_non_sample_records_) { 310 has_event_id = true; 311 event_id = *reinterpret_cast<uint64_t*>(p.get() + header.size - event_id_reverse_pos_in_non_sample_records_); 312 } 313 } 314 if (has_event_id) { 315 auto it = event_id_to_attr_map_.find(event_id); 316 if (it != event_id_to_attr_map_.end()) { 317 attr = &file_attrs_[it->second].attr; 318 } 319 } 320 } 321 auto r = ReadRecordFromOwnedBuffer(*attr, header.type, p.release()); 322 if (r->type() == PERF_RECORD_AUXTRACE) { 323 auto auxtrace = static_cast<AuxTraceRecord*>(r.get()); 324 auxtrace->location.file_offset = header_.data.offset + read_record_size_; 325 read_record_size_ += auxtrace->data->aux_size; 326 if (fseek(record_fp_, auxtrace->data->aux_size, SEEK_CUR) != 0) { 327 PLOG(ERROR) << "fseek() failed"; 328 return nullptr; 329 } 330 } 331 return r; 332 } 333 334 bool RecordFileReader::Read(void* buf, size_t len) { 335 if (len != 0 && fread(buf, len, 1, record_fp_) != 1) { 336 PLOG(FATAL) << "failed to read file " << filename_; 337 return false; 338 } 339 return true; 340 } 341 342 bool RecordFileReader::ReadAtOffset(uint64_t offset, void* buf, size_t len) { 343 if (fseek(record_fp_, offset, SEEK_SET) != 0) { 344 PLOG(ERROR) << "failed to seek to " << offset; 345 return false; 346 } 347 return Read(buf, len); 348 } 349 350 void RecordFileReader::ProcessEventIdRecord(const EventIdRecord& r) { 351 for (size_t i = 0; i < r.count; ++i) { 352 event_ids_for_file_attrs_[r.data[i].attr_id].push_back(r.data[i].event_id); 353 event_id_to_attr_map_[r.data[i].event_id] = r.data[i].attr_id; 354 } 355 } 356 357 size_t RecordFileReader::GetAttrIndexOfRecord(const Record* record) { 358 auto it = event_id_to_attr_map_.find(record->Id()); 359 if (it != event_id_to_attr_map_.end()) { 360 return it->second; 361 } 362 return 0; 363 } 364 365 bool RecordFileReader::ReadFeatureSection(int feature, std::vector<char>* data) { 366 const std::map<int, SectionDesc>& section_map = FeatureSectionDescriptors(); 367 auto it = section_map.find(feature); 368 if (it == section_map.end()) { 369 return false; 370 } 371 SectionDesc section = it->second; 372 data->resize(section.size); 373 if (section.size == 0) { 374 return true; 375 } 376 if (!ReadAtOffset(section.offset, data->data(), data->size())) { 377 return false; 378 } 379 return true; 380 } 381 382 std::vector<std::string> RecordFileReader::ReadCmdlineFeature() { 383 std::vector<char> buf; 384 if (!ReadFeatureSection(FEAT_CMDLINE, &buf)) { 385 return std::vector<std::string>(); 386 } 387 const char* p = buf.data(); 388 const char* end = buf.data() + buf.size(); 389 std::vector<std::string> cmdline; 390 uint32_t arg_count; 391 MoveFromBinaryFormat(arg_count, p); 392 CHECK_LE(p, end); 393 for (size_t i = 0; i < arg_count; ++i) { 394 uint32_t len; 395 MoveFromBinaryFormat(len, p); 396 CHECK_LE(p + len, end); 397 cmdline.push_back(p); 398 p += len; 399 } 400 return cmdline; 401 } 402 403 std::vector<BuildIdRecord> RecordFileReader::ReadBuildIdFeature() { 404 std::vector<char> buf; 405 if (!ReadFeatureSection(FEAT_BUILD_ID, &buf)) { 406 return std::vector<BuildIdRecord>(); 407 } 408 const char* p = buf.data(); 409 const char* end = buf.data() + buf.size(); 410 std::vector<BuildIdRecord> result; 411 while (p < end) { 412 auto header = reinterpret_cast<const perf_event_header*>(p); 413 CHECK_LE(p + header->size, end); 414 char* binary = new char[header->size]; 415 memcpy(binary, p, header->size); 416 p += header->size; 417 BuildIdRecord record(binary); 418 record.OwnBinary(); 419 // Set type explicitly as the perf.data produced by perf doesn't set it. 420 record.SetTypeAndMisc(PERF_RECORD_BUILD_ID, record.misc()); 421 result.push_back(std::move(record)); 422 } 423 return result; 424 } 425 426 std::string RecordFileReader::ReadFeatureString(int feature) { 427 std::vector<char> buf; 428 if (!ReadFeatureSection(feature, &buf)) { 429 return std::string(); 430 } 431 const char* p = buf.data(); 432 const char* end = buf.data() + buf.size(); 433 uint32_t len; 434 MoveFromBinaryFormat(len, p); 435 CHECK_LE(p + len, end); 436 return p; 437 } 438 439 std::vector<uint64_t> RecordFileReader::ReadAuxTraceFeature() { 440 std::vector<char> buf; 441 if (!ReadFeatureSection(FEAT_AUXTRACE, &buf)) { 442 return {}; 443 } 444 std::vector<uint64_t> auxtrace_offset; 445 const char* p = buf.data(); 446 const char* end = buf.data() + buf.size(); 447 while (p < end) { 448 uint64_t offset; 449 uint64_t size; 450 MoveFromBinaryFormat(offset, p); 451 auxtrace_offset.push_back(offset); 452 MoveFromBinaryFormat(size, p); 453 CHECK_EQ(size, AuxTraceRecord::Size()); 454 } 455 return auxtrace_offset; 456 } 457 458 bool RecordFileReader::ReadFileFeature(size_t& read_pos, 459 std::string* file_path, 460 uint32_t* file_type, 461 uint64_t* min_vaddr, 462 uint64_t* file_offset_of_min_vaddr, 463 std::vector<Symbol>* symbols, 464 std::vector<uint64_t>* dex_file_offsets) { 465 auto it = feature_section_descriptors_.find(FEAT_FILE); 466 if (it == feature_section_descriptors_.end()) { 467 return false; 468 } 469 if (read_pos >= it->second.size) { 470 return false; 471 } 472 if (read_pos == 0) { 473 if (fseek(record_fp_, it->second.offset, SEEK_SET) != 0) { 474 PLOG(ERROR) << "fseek() failed"; 475 return false; 476 } 477 } 478 uint32_t size; 479 if (!Read(&size, 4)) { 480 return false; 481 } 482 std::vector<char> buf(size); 483 if (!Read(buf.data(), size)) { 484 return false; 485 } 486 read_pos += 4 + size; 487 const char* p = buf.data(); 488 *file_path = p; 489 p += file_path->size() + 1; 490 MoveFromBinaryFormat(*file_type, p); 491 MoveFromBinaryFormat(*min_vaddr, p); 492 uint32_t symbol_count; 493 MoveFromBinaryFormat(symbol_count, p); 494 symbols->clear(); 495 symbols->reserve(symbol_count); 496 for (uint32_t i = 0; i < symbol_count; ++i) { 497 uint64_t start_vaddr; 498 uint32_t len; 499 MoveFromBinaryFormat(start_vaddr, p); 500 MoveFromBinaryFormat(len, p); 501 std::string name = p; 502 p += name.size() + 1; 503 symbols->emplace_back(name, start_vaddr, len); 504 } 505 dex_file_offsets->clear(); 506 if (*file_type == static_cast<uint32_t>(DSO_DEX_FILE)) { 507 uint32_t offset_count; 508 MoveFromBinaryFormat(offset_count, p); 509 dex_file_offsets->resize(offset_count); 510 MoveFromBinaryFormat(dex_file_offsets->data(), offset_count, p); 511 } 512 *file_offset_of_min_vaddr = std::numeric_limits<uint64_t>::max(); 513 if (*file_type == DSO_ELF_FILE && static_cast<size_t>(p - buf.data()) < size) { 514 MoveFromBinaryFormat(*file_offset_of_min_vaddr, p); 515 } 516 CHECK_EQ(size, static_cast<size_t>(p - buf.data())); 517 return true; 518 } 519 520 bool RecordFileReader::ReadMetaInfoFeature() { 521 if (feature_section_descriptors_.count(FEAT_META_INFO)) { 522 std::vector<char> buf; 523 if (!ReadFeatureSection(FEAT_META_INFO, &buf)) { 524 return false; 525 } 526 const char* p = buf.data(); 527 const char* end = buf.data() + buf.size(); 528 while (p < end) { 529 const char* key = p; 530 const char* value = key + strlen(key) + 1; 531 CHECK(value < end); 532 meta_info_[p] = value; 533 p = value + strlen(value) + 1; 534 } 535 } 536 return true; 537 } 538 539 void RecordFileReader::LoadBuildIdAndFileFeatures(ThreadTree& thread_tree) { 540 std::vector<BuildIdRecord> records = ReadBuildIdFeature(); 541 std::vector<std::pair<std::string, BuildId>> build_ids; 542 for (auto& r : records) { 543 build_ids.push_back(std::make_pair(r.filename, r.build_id)); 544 } 545 Dso::SetBuildIds(build_ids); 546 547 if (HasFeature(PerfFileFormat::FEAT_FILE)) { 548 std::string file_path; 549 uint32_t file_type; 550 uint64_t min_vaddr; 551 uint64_t file_offset_of_min_vaddr; 552 std::vector<Symbol> symbols; 553 std::vector<uint64_t> dex_file_offsets; 554 size_t read_pos = 0; 555 while (ReadFileFeature(read_pos, &file_path, &file_type, &min_vaddr, &file_offset_of_min_vaddr, 556 &symbols, &dex_file_offsets)) { 557 thread_tree.AddDsoInfo(file_path, file_type, min_vaddr, file_offset_of_min_vaddr, &symbols, 558 dex_file_offsets); 559 } 560 } 561 } 562 563 bool RecordFileReader::ReadAuxData(uint32_t cpu, uint64_t aux_offset, void* buf, size_t size) { 564 long saved_pos = ftell(record_fp_); 565 if (saved_pos == -1) { 566 PLOG(ERROR) << "ftell() failed"; 567 return false; 568 } 569 if (aux_data_location_.empty() && !BuildAuxDataLocation()) { 570 return false; 571 } 572 AuxDataLocation* location = nullptr; 573 auto it = aux_data_location_.find(cpu); 574 if (it != aux_data_location_.end()) { 575 auto comp = [](uint64_t aux_offset, const AuxDataLocation& location) { 576 return aux_offset < location.aux_offset; 577 }; 578 auto location_it = std::upper_bound(it->second.begin(), it->second.end(), aux_offset, comp); 579 if (location_it != it->second.begin()) { 580 --location_it; 581 if (location_it->aux_offset + location_it->aux_size >= aux_offset + size) { 582 location = &*location_it; 583 } 584 } 585 } 586 if (location == nullptr) { 587 LOG(ERROR) << "failed to find file offset of aux data: cpu " << cpu << ", aux_offset " 588 << aux_offset << ", size " << size; 589 return false; 590 } 591 if (!ReadAtOffset(aux_offset - location->aux_offset + location->file_offset, buf, size)) { 592 return false; 593 } 594 if (fseek(record_fp_, saved_pos, SEEK_SET) != 0) { 595 PLOG(ERROR) << "fseek() failed"; 596 return false; 597 } 598 return true; 599 } 600 601 bool RecordFileReader::BuildAuxDataLocation() { 602 std::vector<uint64_t> auxtrace_offset = ReadAuxTraceFeature(); 603 if (auxtrace_offset.empty()) { 604 LOG(ERROR) << "failed to read auxtrace feature section"; 605 return false; 606 } 607 std::unique_ptr<char[]> buf(new char[AuxTraceRecord::Size()]); 608 for (auto offset : auxtrace_offset) { 609 if (!ReadAtOffset(offset, buf.get(), AuxTraceRecord::Size())) { 610 return false; 611 } 612 AuxTraceRecord auxtrace(buf.get()); 613 aux_data_location_[auxtrace.data->cpu].emplace_back( 614 auxtrace.data->offset, auxtrace.data->aux_size, offset + auxtrace.size()); 615 } 616 return true; 617 } 618 619 std::vector<std::unique_ptr<Record>> RecordFileReader::DataSection() { 620 std::vector<std::unique_ptr<Record>> records; 621 ReadDataSection([&](std::unique_ptr<Record> record) { 622 records.push_back(std::move(record)); 623 return true; 624 }); 625 return records; 626 } 627