1// Copyright (c) 2013 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 "perf_parser.h" 6 7#include <algorithm> 8#include <cstdio> 9#include <set> 10 11#include "base/logging.h" 12 13#include "address_mapper.h" 14#include "quipper_string.h" 15#include "perf_utils.h" 16 17namespace quipper { 18 19namespace { 20 21struct EventAndTime { 22 ParsedEvent* event; 23 uint64_t time; 24}; 25 26// Returns true if |e1| has an earlier timestamp than |e2|. The args are const 27// pointers instead of references because of the way this function is used when 28// calling std::stable_sort. 29bool CompareParsedEventTimes(const std::unique_ptr<EventAndTime>& e1, 30 const std::unique_ptr<EventAndTime>& e2) { 31 return (e1->time < e2->time); 32} 33 34// Kernel MMAP entry pid appears as -1 35const uint32_t kKernelPid = UINT32_MAX; 36 37// Name and ID of the kernel swapper process. 38const char kSwapperCommandName[] = "swapper"; 39const uint32_t kSwapperPid = 0; 40 41bool IsNullBranchStackEntry(const struct branch_entry& entry) { 42 return (!entry.from && !entry.to); 43} 44 45} // namespace 46 47PerfParser::PerfParser() 48 : kernel_mapper_(new AddressMapper) 49{} 50 51PerfParser::~PerfParser() {} 52 53PerfParser::PerfParser(const PerfParser::Options& options) { 54 options_ = options; 55} 56 57void PerfParser::set_options(const PerfParser::Options& options) { 58 options_ = options; 59} 60 61bool PerfParser::ParseRawEvents() { 62 process_mappers_.clear(); 63 parsed_events_.resize(events_.size()); 64 for (size_t i = 0; i < events_.size(); ++i) { 65 ParsedEvent& parsed_event = parsed_events_[i]; 66 parsed_event.raw_event = events_[i].get(); 67 } 68 MaybeSortParsedEvents(); 69 if (!ProcessEvents()) { 70 return false; 71 } 72 73 if (!options_.discard_unused_events) 74 return true; 75 76 // Some MMAP/MMAP2 events' mapped regions will not have any samples. These 77 // MMAP/MMAP2 events should be dropped. |parsed_events_| should be 78 // reconstructed without these events. 79 size_t write_index = 0; 80 size_t read_index; 81 for (read_index = 0; read_index < parsed_events_.size(); ++read_index) { 82 const ParsedEvent& event = parsed_events_[read_index]; 83 if ((event.raw_event->header.type == PERF_RECORD_MMAP || 84 event.raw_event->header.type == PERF_RECORD_MMAP2) && 85 event.num_samples_in_mmap_region == 0) { 86 continue; 87 } 88 if (read_index != write_index) 89 parsed_events_[write_index] = event; 90 ++write_index; 91 } 92 CHECK_LE(write_index, parsed_events_.size()); 93 parsed_events_.resize(write_index); 94 95 // Now regenerate the sorted event list again. These are pointers to events 96 // so they must be regenerated after a resize() of the ParsedEvent vector. 97 MaybeSortParsedEvents(); 98 99 return true; 100} 101 102void PerfParser::MaybeSortParsedEvents() { 103 if (!(sample_type_ & PERF_SAMPLE_TIME)) { 104 parsed_events_sorted_by_time_.resize(parsed_events_.size()); 105 for (size_t i = 0; i < parsed_events_.size(); ++i) { 106 parsed_events_sorted_by_time_[i] = &parsed_events_[i]; 107 } 108 return; 109 } 110 std::vector<std::unique_ptr<EventAndTime>> events_and_times; 111 events_and_times.resize(parsed_events_.size()); 112 for (size_t i = 0; i < parsed_events_.size(); ++i) { 113 std::unique_ptr<EventAndTime> event_and_time(new EventAndTime); 114 115 // Store the timestamp and event pointer in an array. 116 event_and_time->event = &parsed_events_[i]; 117 118 struct perf_sample sample_info; 119 PerfSampleCustodian custodian(sample_info); 120 CHECK(ReadPerfSampleInfo(*parsed_events_[i].raw_event, &sample_info)); 121 event_and_time->time = sample_info.time; 122 123 events_and_times[i] = std::move(event_and_time); 124 } 125 // Sort the events based on timestamp, and then populate the sorted event 126 // vector in sorted order. 127 std::stable_sort(events_and_times.begin(), events_and_times.end(), 128 CompareParsedEventTimes); 129 130 parsed_events_sorted_by_time_.resize(events_and_times.size()); 131 for (unsigned int i = 0; i < events_and_times.size(); ++i) { 132 parsed_events_sorted_by_time_[i] = events_and_times[i]->event; 133 } 134} 135 136bool PerfParser::ProcessEvents() { 137 memset(&stats_, 0, sizeof(stats_)); 138 139 stats_.did_remap = false; // Explicitly clear the remap flag. 140 141 // Pid 0 is called the swapper process. Even though perf does not record a 142 // COMM event for pid 0, we act like we did receive a COMM event for it. Perf 143 // does this itself, example: 144 // http://lxr.free-electrons.com/source/tools/perf/util/session.c#L1120 145 commands_.insert(kSwapperCommandName); 146 pidtid_to_comm_map_[std::make_pair(kSwapperPid, kSwapperPid)] = 147 &(*commands_.find(kSwapperCommandName)); 148 149 // NB: Not necessarily actually sorted by time. 150 for (unsigned int i = 0; i < parsed_events_sorted_by_time_.size(); ++i) { 151 ParsedEvent& parsed_event = *parsed_events_sorted_by_time_[i]; 152 event_t& event = *parsed_event.raw_event; 153 switch (event.header.type) { 154 case PERF_RECORD_SAMPLE: 155 // SAMPLE doesn't have any fields to log at a fixed, 156 // previously-endian-swapped location. This used to log ip. 157 VLOG(1) << "SAMPLE"; 158 ++stats_.num_sample_events; 159 160 if (MapSampleEvent(&parsed_event)) { 161 ++stats_.num_sample_events_mapped; 162 } 163 break; 164 case PERF_RECORD_MMAP: { 165 VLOG(1) << "MMAP: " << event.mmap.filename; 166 ++stats_.num_mmap_events; 167 // Use the array index of the current mmap event as a unique identifier. 168 CHECK(MapMmapEvent(&event.mmap, i)) << "Unable to map MMAP event!"; 169 // No samples in this MMAP region yet, hopefully. 170 parsed_event.num_samples_in_mmap_region = 0; 171 DSOInfo dso_info; 172 // TODO(sque): Add Build ID as well. 173 dso_info.name = event.mmap.filename; 174 dso_set_.insert(dso_info); 175 break; 176 } 177 case PERF_RECORD_MMAP2: { 178 VLOG(1) << "MMAP2: " << event.mmap2.filename; 179 ++stats_.num_mmap_events; 180 // Use the array index of the current mmap event as a unique identifier. 181 CHECK(MapMmapEvent(&event.mmap2, i)) << "Unable to map MMAP2 event!"; 182 // No samples in this MMAP region yet, hopefully. 183 parsed_event.num_samples_in_mmap_region = 0; 184 DSOInfo dso_info; 185 // TODO(sque): Add Build ID as well. 186 dso_info.name = event.mmap2.filename; 187 dso_set_.insert(dso_info); 188 break; 189 } 190 case PERF_RECORD_FORK: 191 VLOG(1) << "FORK: " << event.fork.ppid << ":" << event.fork.ptid 192 << " -> " << event.fork.pid << ":" << event.fork.tid; 193 ++stats_.num_fork_events; 194 CHECK(MapForkEvent(event.fork)) << "Unable to map FORK event!"; 195 break; 196 case PERF_RECORD_EXIT: 197 // EXIT events have the same structure as FORK events. 198 VLOG(1) << "EXIT: " << event.fork.ppid << ":" << event.fork.ptid; 199 ++stats_.num_exit_events; 200 break; 201 case PERF_RECORD_COMM: 202 VLOG(1) << "COMM: " << event.comm.pid << ":" << event.comm.tid << ": " 203 << event.comm.comm; 204 ++stats_.num_comm_events; 205 CHECK(MapCommEvent(event.comm)); 206 commands_.insert(event.comm.comm); 207 pidtid_to_comm_map_[std::make_pair(event.comm.pid, event.comm.tid)] = 208 &(*commands_.find(event.comm.comm)); 209 break; 210 case PERF_RECORD_LOST: 211 case PERF_RECORD_THROTTLE: 212 case PERF_RECORD_UNTHROTTLE: 213 case PERF_RECORD_READ: 214 case PERF_RECORD_MAX: 215 VLOG(1) << "Parsed event type: " << event.header.type 216 << ". Doing nothing."; 217 break; 218 case SIMPLE_PERF_RECORD_KERNEL_SYMBOL: 219 case SIMPLE_PERF_RECORD_DSO: 220 case SIMPLE_PERF_RECORD_SYMBOL: 221 case SIMPLE_PERF_RECORD_SPLIT: 222 case SIMPLE_PERF_RECORD_SPLIT_END: 223 break; 224 default: 225 LOG(ERROR) << "Unknown event type: " << event.header.type; 226 return false; 227 } 228 } 229 230 // Print stats collected from parsing. 231 DLOG(INFO) << "Parser processed: " 232 << stats_.num_mmap_events << " MMAP/MMAP2 events, " 233 << stats_.num_comm_events << " COMM events, " 234 << stats_.num_fork_events << " FORK events, " 235 << stats_.num_exit_events << " EXIT events, " 236 << stats_.num_sample_events << " SAMPLE events, " 237 << stats_.num_sample_events_mapped << " of these were mapped"; 238 239 float sample_mapping_percentage = 240 static_cast<float>(stats_.num_sample_events_mapped) / 241 stats_.num_sample_events * 100.; 242 float threshold = options_.sample_mapping_percentage_threshold; 243 if (sample_mapping_percentage < threshold) { 244 LOG(WARNING) << "Mapped " << static_cast<int>(sample_mapping_percentage) 245 << "% of samples, expected at least " 246 << static_cast<int>(threshold) << "%"; 247 return false; 248 } 249 stats_.did_remap = options_.do_remap; 250 return true; 251} 252 253bool PerfParser::MapSampleEvent(ParsedEvent* parsed_event) { 254 bool mapping_failed = false; 255 256 // Find the associated command. 257 if (!(sample_type_ & PERF_SAMPLE_IP && sample_type_ & PERF_SAMPLE_TID)) 258 return false; 259 perf_sample sample_info; 260 PerfSampleCustodian custodian(sample_info); 261 if (!ReadPerfSampleInfo(*parsed_event->raw_event, &sample_info)) 262 return false; 263 PidTid pidtid = std::make_pair(sample_info.pid, sample_info.tid); 264 const auto comm_iter = pidtid_to_comm_map_.find(pidtid); 265 if (comm_iter != pidtid_to_comm_map_.end()) { 266 parsed_event->set_command(comm_iter->second); 267 } 268 269 const uint64_t unmapped_event_ip = sample_info.ip; 270 271 // Map the event IP itself. 272 if (!MapIPAndPidAndGetNameAndOffset(sample_info.ip, 273 sample_info.pid, 274 &sample_info.ip, 275 &parsed_event->dso_and_offset)) { 276 mapping_failed = true; 277 } 278 279 if (sample_info.callchain && 280 !MapCallchain(sample_info.ip, 281 sample_info.pid, 282 unmapped_event_ip, 283 sample_info.callchain, 284 parsed_event)) { 285 mapping_failed = true; 286 } 287 288 if (sample_info.branch_stack && 289 !MapBranchStack(sample_info.pid, 290 sample_info.branch_stack, 291 parsed_event)) { 292 mapping_failed = true; 293 } 294 295 if (options_.do_remap) { 296 // Write the remapped data back to the raw event regardless of 297 // whether it was entirely successfully remapped. A single failed 298 // remap should not invalidate all the other remapped entries. 299 if (!WritePerfSampleInfo(sample_info, parsed_event->raw_event)) { 300 LOG(ERROR) << "Failed to write back remapped sample info."; 301 return false; 302 } 303 } 304 305 return !mapping_failed; 306} 307 308bool PerfParser::MapCallchain(const uint64_t ip, 309 const uint32_t pid, 310 const uint64_t original_event_addr, 311 struct ip_callchain* callchain, 312 ParsedEvent* parsed_event) { 313 if (!callchain) { 314 LOG(ERROR) << "NULL call stack data."; 315 return false; 316 } 317 318 bool mapping_failed = false; 319 320 // If the callchain's length is 0, there is no work to do. 321 if (callchain->nr == 0) 322 return true; 323 324 // Keeps track of whether the current entry is kernel or user. 325 parsed_event->callchain.resize(callchain->nr); 326 int num_entries_mapped = 0; 327 for (unsigned int j = 0; j < callchain->nr; ++j) { 328 uint64_t entry = callchain->ips[j]; 329 // When a callchain context entry is found, do not attempt to symbolize it. 330 if (entry >= PERF_CONTEXT_MAX) { 331 continue; 332 } 333 // The sample address has already been mapped so no need to map it. 334 if (entry == original_event_addr) { 335 callchain->ips[j] = ip; 336 continue; 337 } 338 if (!MapIPAndPidAndGetNameAndOffset( 339 entry, 340 pid, 341 &callchain->ips[j], 342 &parsed_event->callchain[num_entries_mapped++])) { 343 mapping_failed = true; 344 } 345 } 346 // Not all the entries were mapped. Trim |parsed_event->callchain| to 347 // remove unused entries at the end. 348 parsed_event->callchain.resize(num_entries_mapped); 349 350 return !mapping_failed; 351} 352 353bool PerfParser::MapBranchStack(const uint32_t pid, 354 struct branch_stack* branch_stack, 355 ParsedEvent* parsed_event) { 356 if (!branch_stack) { 357 LOG(ERROR) << "NULL branch stack data."; 358 return false; 359 } 360 361 // First, trim the branch stack to remove trailing null entries. 362 size_t trimmed_size = 0; 363 for (size_t i = 0; i < branch_stack->nr; ++i) { 364 // Count the number of non-null entries before the first null entry. 365 if (IsNullBranchStackEntry(branch_stack->entries[i])) { 366 break; 367 } 368 ++trimmed_size; 369 } 370 371 // If a null entry was found, make sure all subsequent null entries are NULL 372 // as well. 373 for (size_t i = trimmed_size; i < branch_stack->nr; ++i) { 374 const struct branch_entry& entry = branch_stack->entries[i]; 375 if (!IsNullBranchStackEntry(entry)) { 376 LOG(ERROR) << "Non-null branch stack entry found after null entry: " 377 << reinterpret_cast<void*>(entry.from) << " -> " 378 << reinterpret_cast<void*>(entry.to); 379 return false; 380 } 381 } 382 383 // Map branch stack addresses. 384 parsed_event->branch_stack.resize(trimmed_size); 385 for (unsigned int i = 0; i < trimmed_size; ++i) { 386 struct branch_entry& entry = branch_stack->entries[i]; 387 ParsedEvent::BranchEntry& parsed_entry = parsed_event->branch_stack[i]; 388 if (!MapIPAndPidAndGetNameAndOffset(entry.from, 389 pid, 390 &entry.from, 391 &parsed_entry.from)) { 392 return false; 393 } 394 if (!MapIPAndPidAndGetNameAndOffset(entry.to, 395 pid, 396 &entry.to, 397 &parsed_entry.to)) { 398 return false; 399 } 400 parsed_entry.predicted = entry.flags.predicted; 401 // Either predicted or mispredicted, not both. But don't use a CHECK here, 402 // just exit gracefully because it's a minor issue. 403 if (entry.flags.predicted == entry.flags.mispred) { 404 LOG(ERROR) << "Branch stack entry predicted and mispred flags " 405 << "both have value " << entry.flags.mispred; 406 return false; 407 } 408 } 409 410 return true; 411} 412 413bool PerfParser::MapIPAndPidAndGetNameAndOffset( 414 uint64_t ip, 415 uint32_t pid, 416 uint64_t* new_ip, 417 ParsedEvent::DSOAndOffset* dso_and_offset) { 418 419 // Attempt to find the synthetic address of the IP sample in this order: 420 // 1. Address space of its own process. 421 // 2. Address space of the kernel. 422 423 uint64_t mapped_addr = 0; 424 425 // Sometimes the first event we see is a SAMPLE event and we don't have the 426 // time to create an address mapper for a process. Example, for pid 0. 427 AddressMapper* mapper = GetOrCreateProcessMapper(pid).first; 428 bool mapped = mapper->GetMappedAddress(ip, &mapped_addr); 429 if (!mapped) { 430 mapper = kernel_mapper_.get(); 431 mapped = mapper->GetMappedAddress(ip, &mapped_addr); 432 } 433 434 // TODO(asharif): What should we do when we cannot map a SAMPLE event? 435 if (mapped) { 436 if (dso_and_offset) { 437 uint64_t id = kuint64max; 438 CHECK(mapper->GetMappedIDAndOffset(ip, &id, &dso_and_offset->offset_)); 439 // Make sure the ID points to a valid event. 440 CHECK_LE(id, parsed_events_sorted_by_time_.size()); 441 ParsedEvent* parsed_event = parsed_events_sorted_by_time_[id]; 442 const event_t* raw_event = parsed_event->raw_event; 443 444 DSOInfo dso_info; 445 if (raw_event->header.type == PERF_RECORD_MMAP) { 446 dso_info.name = raw_event->mmap.filename; 447 } else if (raw_event->header.type == PERF_RECORD_MMAP2) { 448 dso_info.name = raw_event->mmap2.filename; 449 } else { 450 LOG(FATAL) << "Expected MMAP or MMAP2 event"; 451 } 452 453 // Find the mmap DSO filename in the set of known DSO names. 454 // TODO(sque): take build IDs into account. 455 std::set<DSOInfo>::const_iterator dso_iter = dso_set_.find(dso_info); 456 CHECK(dso_iter != dso_set_.end()); 457 dso_and_offset->dso_info_ = &(*dso_iter); 458 459 ++parsed_event->num_samples_in_mmap_region; 460 } 461 if (options_.do_remap) 462 *new_ip = mapped_addr; 463 } 464 return mapped; 465} 466 467bool PerfParser::MapMmapEvent(uint64_t id, 468 uint32_t pid, 469 uint64_t* p_start, 470 uint64_t* p_len, 471 uint64_t* p_pgoff) 472{ 473 // We need to hide only the real kernel addresses. However, to make things 474 // more secure, and make the mapping idempotent, we should remap all 475 // addresses, both kernel and non-kernel. 476 AddressMapper* mapper = 477 (pid == kKernelPid ? kernel_mapper_.get() : 478 GetOrCreateProcessMapper(pid).first); 479 480 uint64_t start = *p_start; 481 uint64_t len = *p_len; 482 uint64_t pgoff = *p_pgoff; 483 484 // |id| == 0 corresponds to the kernel mmap. We have several cases here: 485 // 486 // For ARM and x86, in sudo mode, pgoff == start, example: 487 // start=0x80008200 488 // pgoff=0x80008200 489 // len =0xfffffff7ff7dff 490 // 491 // For x86-64, in sudo mode, pgoff is between start and start + len. SAMPLE 492 // events lie between pgoff and pgoff + length of the real kernel binary, 493 // example: 494 // start=0x3bc00000 495 // pgoff=0xffffffffbcc00198 496 // len =0xffffffff843fffff 497 // SAMPLE events will be found after pgoff. For kernels with ASLR, pgoff will 498 // be something only visible to the root user, and will be randomized at 499 // startup. With |remap| set to true, we should hide pgoff in this case. So we 500 // normalize all SAMPLE events relative to pgoff. 501 // 502 // For non-sudo mode, the kernel will be mapped from 0 to the pointer limit, 503 // example: 504 // start=0x0 505 // pgoff=0x0 506 // len =0xffffffff 507 if (id == 0) { 508 // If pgoff is between start and len, we normalize the event by setting 509 // start to be pgoff just like how it is for ARM and x86. We also set len to 510 // be a much smaller number (closer to the real length of the kernel binary) 511 // because SAMPLEs are actually only seen between |event->pgoff| and 512 // |event->pgoff + kernel text size|. 513 if (pgoff > start && pgoff < start + len) { 514 len = len + start - pgoff; 515 start = pgoff; 516 } 517 // For kernels with ALSR pgoff is critical information that should not be 518 // revealed when |remap| is true. 519 pgoff = 0; 520 } 521 522 if (!mapper->MapWithID(start, len, id, pgoff, true)) { 523 mapper->DumpToLog(); 524 return false; 525 } 526 527 if (options_.do_remap) { 528 uint64_t mapped_addr; 529 CHECK(mapper->GetMappedAddress(start, &mapped_addr)); 530 *p_start = mapped_addr; 531 *p_len = len; 532 *p_pgoff = pgoff; 533 } 534 return true; 535} 536 537std::pair<AddressMapper*, bool> PerfParser::GetOrCreateProcessMapper( 538 uint32_t pid, uint32_t *ppid) { 539 const auto& search = process_mappers_.find(pid); 540 if (search != process_mappers_.end()) { 541 return std::make_pair(search->second.get(), false); 542 } 543 544 std::unique_ptr<AddressMapper> mapper; 545 const auto& parent_mapper = (ppid ? process_mappers_.find(*ppid) : process_mappers_.end()); 546 if (parent_mapper != process_mappers_.end()) 547 mapper.reset(new AddressMapper(*parent_mapper->second)); 548 else 549 mapper.reset(new AddressMapper()); 550 551 const auto inserted = 552 process_mappers_.insert(search, std::make_pair(pid, std::move(mapper))); 553 return std::make_pair(inserted->second.get(), true); 554} 555 556bool PerfParser::MapCommEvent(const struct comm_event& event) { 557 GetOrCreateProcessMapper(event.pid); 558 return true; 559} 560 561bool PerfParser::MapForkEvent(const struct fork_event& event) { 562 PidTid parent = std::make_pair(event.ppid, event.ptid); 563 PidTid child = std::make_pair(event.pid, event.tid); 564 if (parent != child && 565 pidtid_to_comm_map_.find(parent) != pidtid_to_comm_map_.end()) { 566 pidtid_to_comm_map_[child] = pidtid_to_comm_map_[parent]; 567 } 568 569 const uint32_t pid = event.pid; 570 571 // If the parent and child pids are the same, this is just a new thread 572 // within the same process, so don't do anything. 573 if (event.ppid == pid) 574 return true; 575 576 uint32_t ppid = event.ppid; 577 if (!GetOrCreateProcessMapper(pid, &ppid).second) { 578 DLOG(INFO) << "Found an existing process mapper with pid: " << pid; 579 } 580 581 return true; 582} 583 584} // namespace quipper 585