17e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 27e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// Use of this source code is governed by a BSD-style license that can be 37e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// found in the LICENSE file. 47e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 57e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include "perf_parser.h" 67e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 77e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include <algorithm> 87e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include <cstdio> 97e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include <set> 107e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 117e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include "base/logging.h" 127e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 137e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include "address_mapper.h" 147e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include "quipper_string.h" 157e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh#include "perf_utils.h" 167e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 177e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshnamespace quipper { 187e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 197e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshnamespace { 207e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 217e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshstruct EventAndTime { 227e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh ParsedEvent* event; 237e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh uint64_t time; 247e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh}; 257e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 267e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// Returns true if |e1| has an earlier timestamp than |e2|. The args are const 277e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// pointers instead of references because of the way this function is used when 287e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// calling std::stable_sort. 297e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshbool CompareParsedEventTimes(const std::unique_ptr<EventAndTime>& e1, 307e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh const std::unique_ptr<EventAndTime>& e2) { 317e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return (e1->time < e2->time); 327e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh} 337e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 347e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// Kernel MMAP entry pid appears as -1 357e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshconst uint32_t kKernelPid = UINT32_MAX; 367e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 377e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh// Name and ID of the kernel swapper process. 387e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshconst char kSwapperCommandName[] = "swapper"; 397e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshconst uint32_t kSwapperPid = 0; 407e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 417e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshbool IsNullBranchStackEntry(const struct branch_entry& entry) { 427e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return (!entry.from && !entry.to); 437e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh} 447e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 457e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh} // namespace 467e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 477e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshPerfParser::PerfParser() 487e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh : kernel_mapper_(new AddressMapper) 497e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh{} 507e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 517e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshPerfParser::~PerfParser() {} 527e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 537e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshPerfParser::PerfParser(const PerfParser::Options& options) { 547e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh options_ = options; 557e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh} 567e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 577e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshvoid PerfParser::set_options(const PerfParser::Options& options) { 587e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh options_ = options; 597e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh} 607e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 617e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshbool PerfParser::ParseRawEvents() { 627e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh process_mappers_.clear(); 637e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh parsed_events_.resize(events_.size()); 647e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh for (size_t i = 0; i < events_.size(); ++i) { 657e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh ParsedEvent& parsed_event = parsed_events_[i]; 667e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh parsed_event.raw_event = events_[i].get(); 677e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 687e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh MaybeSortParsedEvents(); 697e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (!ProcessEvents()) { 707e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return false; 717e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 727e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 737e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (!options_.discard_unused_events) 747e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return true; 757e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 767e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Some MMAP/MMAP2 events' mapped regions will not have any samples. These 777e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // MMAP/MMAP2 events should be dropped. |parsed_events_| should be 787e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // reconstructed without these events. 797e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh size_t write_index = 0; 807e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh size_t read_index; 817e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh for (read_index = 0; read_index < parsed_events_.size(); ++read_index) { 827e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh const ParsedEvent& event = parsed_events_[read_index]; 837e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if ((event.raw_event->header.type == PERF_RECORD_MMAP || 847e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh event.raw_event->header.type == PERF_RECORD_MMAP2) && 857e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh event.num_samples_in_mmap_region == 0) { 867e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh continue; 877e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 887e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (read_index != write_index) 897e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh parsed_events_[write_index] = event; 907e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh ++write_index; 917e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 927e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh CHECK_LE(write_index, parsed_events_.size()); 937e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh parsed_events_.resize(write_index); 947e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 957e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Now regenerate the sorted event list again. These are pointers to events 967e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // so they must be regenerated after a resize() of the ParsedEvent vector. 977e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh MaybeSortParsedEvents(); 987e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 997e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return true; 1007e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh} 1017e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 1027e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshvoid PerfParser::MaybeSortParsedEvents() { 1037e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (!(sample_type_ & PERF_SAMPLE_TIME)) { 1047e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh parsed_events_sorted_by_time_.resize(parsed_events_.size()); 1057e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh for (size_t i = 0; i < parsed_events_.size(); ++i) { 1067e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh parsed_events_sorted_by_time_[i] = &parsed_events_[i]; 1077e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 1087e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return; 1097e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 1107e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh std::vector<std::unique_ptr<EventAndTime>> events_and_times; 1117e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh events_and_times.resize(parsed_events_.size()); 1127e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh for (size_t i = 0; i < parsed_events_.size(); ++i) { 1137e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh std::unique_ptr<EventAndTime> event_and_time(new EventAndTime); 1147e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 1157e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Store the timestamp and event pointer in an array. 1167e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh event_and_time->event = &parsed_events_[i]; 1177e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 1187e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh struct perf_sample sample_info; 1197e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh PerfSampleCustodian custodian(sample_info); 1207e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh CHECK(ReadPerfSampleInfo(*parsed_events_[i].raw_event, &sample_info)); 1217e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh event_and_time->time = sample_info.time; 1227e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 1237e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh events_and_times[i] = std::move(event_and_time); 1247e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 1257e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Sort the events based on timestamp, and then populate the sorted event 1267e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // vector in sorted order. 1277e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh std::stable_sort(events_and_times.begin(), events_and_times.end(), 1287e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh CompareParsedEventTimes); 1297e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 1307e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh parsed_events_sorted_by_time_.resize(events_and_times.size()); 1317e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh for (unsigned int i = 0; i < events_and_times.size(); ++i) { 1327e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh parsed_events_sorted_by_time_[i] = events_and_times[i]->event; 1337e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 1347e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh} 1357e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 1367e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshbool PerfParser::ProcessEvents() { 1377e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh memset(&stats_, 0, sizeof(stats_)); 1387e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 1397e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh stats_.did_remap = false; // Explicitly clear the remap flag. 1407e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 1417e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Pid 0 is called the swapper process. Even though perf does not record a 1427e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // COMM event for pid 0, we act like we did receive a COMM event for it. Perf 1437e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // does this itself, example: 1447e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // http://lxr.free-electrons.com/source/tools/perf/util/session.c#L1120 1457e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh commands_.insert(kSwapperCommandName); 1467e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh pidtid_to_comm_map_[std::make_pair(kSwapperPid, kSwapperPid)] = 1477e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh &(*commands_.find(kSwapperCommandName)); 1487e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 1497e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // NB: Not necessarily actually sorted by time. 1507e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh for (unsigned int i = 0; i < parsed_events_sorted_by_time_.size(); ++i) { 1517e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh ParsedEvent& parsed_event = *parsed_events_sorted_by_time_[i]; 1527e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh event_t& event = *parsed_event.raw_event; 1537e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh switch (event.header.type) { 1547e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh case PERF_RECORD_SAMPLE: 1557e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // SAMPLE doesn't have any fields to log at a fixed, 1567e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // previously-endian-swapped location. This used to log ip. 1577e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh VLOG(1) << "SAMPLE"; 1587e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh ++stats_.num_sample_events; 1597e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 1607e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (MapSampleEvent(&parsed_event)) { 1617e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh ++stats_.num_sample_events_mapped; 1627e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 1637e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh break; 1647e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh case PERF_RECORD_MMAP: { 1657e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh VLOG(1) << "MMAP: " << event.mmap.filename; 1667e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh ++stats_.num_mmap_events; 1677e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Use the array index of the current mmap event as a unique identifier. 1687e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh CHECK(MapMmapEvent(&event.mmap, i)) << "Unable to map MMAP event!"; 1697e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // No samples in this MMAP region yet, hopefully. 1707e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh parsed_event.num_samples_in_mmap_region = 0; 1717e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh DSOInfo dso_info; 1727e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // TODO(sque): Add Build ID as well. 1737e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh dso_info.name = event.mmap.filename; 1747e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh dso_set_.insert(dso_info); 1757e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh break; 1767e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 1777e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh case PERF_RECORD_MMAP2: { 1787e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh VLOG(1) << "MMAP2: " << event.mmap2.filename; 1797e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh ++stats_.num_mmap_events; 1807e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Use the array index of the current mmap event as a unique identifier. 1817e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh CHECK(MapMmapEvent(&event.mmap2, i)) << "Unable to map MMAP2 event!"; 1827e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // No samples in this MMAP region yet, hopefully. 1837e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh parsed_event.num_samples_in_mmap_region = 0; 1847e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh DSOInfo dso_info; 1857e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // TODO(sque): Add Build ID as well. 1867e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh dso_info.name = event.mmap2.filename; 1877e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh dso_set_.insert(dso_info); 1887e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh break; 1897e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 1907e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh case PERF_RECORD_FORK: 1917e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh VLOG(1) << "FORK: " << event.fork.ppid << ":" << event.fork.ptid 1927e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh << " -> " << event.fork.pid << ":" << event.fork.tid; 1937e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh ++stats_.num_fork_events; 1947e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh CHECK(MapForkEvent(event.fork)) << "Unable to map FORK event!"; 1957e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh break; 1967e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh case PERF_RECORD_EXIT: 1977e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // EXIT events have the same structure as FORK events. 1987e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh VLOG(1) << "EXIT: " << event.fork.ppid << ":" << event.fork.ptid; 1997e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh ++stats_.num_exit_events; 2007e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh break; 2017e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh case PERF_RECORD_COMM: 2027e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh VLOG(1) << "COMM: " << event.comm.pid << ":" << event.comm.tid << ": " 2037e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh << event.comm.comm; 2047e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh ++stats_.num_comm_events; 2057e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh CHECK(MapCommEvent(event.comm)); 2067e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh commands_.insert(event.comm.comm); 2077e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh pidtid_to_comm_map_[std::make_pair(event.comm.pid, event.comm.tid)] = 2087e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh &(*commands_.find(event.comm.comm)); 2097e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh break; 2107e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh case PERF_RECORD_LOST: 2117e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh case PERF_RECORD_THROTTLE: 2127e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh case PERF_RECORD_UNTHROTTLE: 2137e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh case PERF_RECORD_READ: 2147e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh case PERF_RECORD_MAX: 2157e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh VLOG(1) << "Parsed event type: " << event.header.type 2167e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh << ". Doing nothing."; 2177e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh break; 2187e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh default: 2197e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh LOG(ERROR) << "Unknown event type: " << event.header.type; 2207e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return false; 2217e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 2227e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 2237e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 2247e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Print stats collected from parsing. 2257e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh DLOG(INFO) << "Parser processed: " 2267e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh << stats_.num_mmap_events << " MMAP/MMAP2 events, " 2277e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh << stats_.num_comm_events << " COMM events, " 2287e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh << stats_.num_fork_events << " FORK events, " 2297e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh << stats_.num_exit_events << " EXIT events, " 2307e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh << stats_.num_sample_events << " SAMPLE events, " 2317e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh << stats_.num_sample_events_mapped << " of these were mapped"; 2327e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 2337e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh float sample_mapping_percentage = 2347e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh static_cast<float>(stats_.num_sample_events_mapped) / 2357e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh stats_.num_sample_events * 100.; 2367e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh float threshold = options_.sample_mapping_percentage_threshold; 2377e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (sample_mapping_percentage < threshold) { 2387e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh LOG(WARNING) << "Mapped " << static_cast<int>(sample_mapping_percentage) 2397e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh << "% of samples, expected at least " 2407e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh << static_cast<int>(threshold) << "%"; 2417e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return false; 2427e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 2437e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh stats_.did_remap = options_.do_remap; 2447e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return true; 2457e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh} 2467e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 2477e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshbool PerfParser::MapSampleEvent(ParsedEvent* parsed_event) { 2487e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh bool mapping_failed = false; 2497e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 2507e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Find the associated command. 2517e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (!(sample_type_ & PERF_SAMPLE_IP && sample_type_ & PERF_SAMPLE_TID)) 2527e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return false; 2537e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh perf_sample sample_info; 2547e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh PerfSampleCustodian custodian(sample_info); 2557e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (!ReadPerfSampleInfo(*parsed_event->raw_event, &sample_info)) 2567e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return false; 2577e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh PidTid pidtid = std::make_pair(sample_info.pid, sample_info.tid); 2587e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh const auto comm_iter = pidtid_to_comm_map_.find(pidtid); 2597e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (comm_iter != pidtid_to_comm_map_.end()) { 2607e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh parsed_event->set_command(comm_iter->second); 2617e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 2627e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 2637e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh const uint64_t unmapped_event_ip = sample_info.ip; 2647e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 2657e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Map the event IP itself. 2667e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (!MapIPAndPidAndGetNameAndOffset(sample_info.ip, 2677e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh sample_info.pid, 2687e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh &sample_info.ip, 2697e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh &parsed_event->dso_and_offset)) { 2707e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh mapping_failed = true; 2717e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 2727e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 2737e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (sample_info.callchain && 2747e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh !MapCallchain(sample_info.ip, 2757e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh sample_info.pid, 2767e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh unmapped_event_ip, 2777e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh sample_info.callchain, 2787e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh parsed_event)) { 2797e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh mapping_failed = true; 2807e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 2817e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 2827e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (sample_info.branch_stack && 2837e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh !MapBranchStack(sample_info.pid, 2847e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh sample_info.branch_stack, 2857e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh parsed_event)) { 2867e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh mapping_failed = true; 2877e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 2887e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 2897e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Write the remapped data back to the raw event regardless of whether it was 2907e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // entirely successfully remapped. A single failed remap should not 2917e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // invalidate all the other remapped entries. 2927e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (!WritePerfSampleInfo(sample_info, parsed_event->raw_event)) { 2937e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh LOG(ERROR) << "Failed to write back remapped sample info."; 2947e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return false; 2957e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 2967e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 2977e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return !mapping_failed; 2987e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh} 2997e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 3007e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshbool PerfParser::MapCallchain(const uint64_t ip, 3017e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh const uint32_t pid, 3027e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh const uint64_t original_event_addr, 3037e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh struct ip_callchain* callchain, 3047e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh ParsedEvent* parsed_event) { 3057e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (!callchain) { 3067e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh LOG(ERROR) << "NULL call stack data."; 3077e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return false; 3087e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 3097e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 3107e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh bool mapping_failed = false; 3117e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 3127e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // If the callchain's length is 0, there is no work to do. 3137e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (callchain->nr == 0) 3147e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return true; 3157e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 3167e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Keeps track of whether the current entry is kernel or user. 3177e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh parsed_event->callchain.resize(callchain->nr); 3187e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh int num_entries_mapped = 0; 3197e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh for (unsigned int j = 0; j < callchain->nr; ++j) { 3207e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh uint64_t entry = callchain->ips[j]; 3217e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // When a callchain context entry is found, do not attempt to symbolize it. 3227e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (entry >= PERF_CONTEXT_MAX) { 3237e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh continue; 3247e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 3257e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // The sample address has already been mapped so no need to map it. 3267e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (entry == original_event_addr) { 3277e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh callchain->ips[j] = ip; 3287e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh continue; 3297e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 3307e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (!MapIPAndPidAndGetNameAndOffset( 3317e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh entry, 3327e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh pid, 3337e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh &callchain->ips[j], 3347e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh &parsed_event->callchain[num_entries_mapped++])) { 3357e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh mapping_failed = true; 3367e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 3377e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 3387e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Not all the entries were mapped. Trim |parsed_event->callchain| to 3397e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // remove unused entries at the end. 3407e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh parsed_event->callchain.resize(num_entries_mapped); 3417e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 3427e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return !mapping_failed; 3437e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh} 3447e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 3457e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshbool PerfParser::MapBranchStack(const uint32_t pid, 3467e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh struct branch_stack* branch_stack, 3477e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh ParsedEvent* parsed_event) { 3487e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (!branch_stack) { 3497e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh LOG(ERROR) << "NULL branch stack data."; 3507e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return false; 3517e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 3527e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 3537e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // First, trim the branch stack to remove trailing null entries. 3547e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh size_t trimmed_size = 0; 3557e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh for (size_t i = 0; i < branch_stack->nr; ++i) { 3567e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Count the number of non-null entries before the first null entry. 3577e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (IsNullBranchStackEntry(branch_stack->entries[i])) { 3587e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh break; 3597e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 3607e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh ++trimmed_size; 3617e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 3627e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 3637e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // If a null entry was found, make sure all subsequent null entries are NULL 3647e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // as well. 3657e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh for (size_t i = trimmed_size; i < branch_stack->nr; ++i) { 3667e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh const struct branch_entry& entry = branch_stack->entries[i]; 3677e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (!IsNullBranchStackEntry(entry)) { 3687e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh LOG(ERROR) << "Non-null branch stack entry found after null entry: " 3697e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh << reinterpret_cast<void*>(entry.from) << " -> " 3707e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh << reinterpret_cast<void*>(entry.to); 3717e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return false; 3727e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 3737e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 3747e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 3757e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Map branch stack addresses. 3767e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh parsed_event->branch_stack.resize(trimmed_size); 3777e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh for (unsigned int i = 0; i < trimmed_size; ++i) { 3787e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh struct branch_entry& entry = branch_stack->entries[i]; 3797e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh ParsedEvent::BranchEntry& parsed_entry = parsed_event->branch_stack[i]; 3807e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (!MapIPAndPidAndGetNameAndOffset(entry.from, 3817e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh pid, 3827e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh &entry.from, 3837e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh &parsed_entry.from)) { 3847e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return false; 3857e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 3867e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (!MapIPAndPidAndGetNameAndOffset(entry.to, 3877e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh pid, 3887e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh &entry.to, 3897e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh &parsed_entry.to)) { 3907e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return false; 3917e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 3927e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh parsed_entry.predicted = entry.flags.predicted; 3937e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Either predicted or mispredicted, not both. But don't use a CHECK here, 3947e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // just exit gracefully because it's a minor issue. 3957e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (entry.flags.predicted == entry.flags.mispred) { 3967e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh LOG(ERROR) << "Branch stack entry predicted and mispred flags " 3977e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh << "both have value " << entry.flags.mispred; 3987e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return false; 3997e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 4007e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 4017e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 4027e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return true; 4037e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh} 4047e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 4057e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshbool PerfParser::MapIPAndPidAndGetNameAndOffset( 4067e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh uint64_t ip, 4077e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh uint32_t pid, 4087e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh uint64_t* new_ip, 4097e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh ParsedEvent::DSOAndOffset* dso_and_offset) { 4107e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 4117e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Attempt to find the synthetic address of the IP sample in this order: 4127e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // 1. Address space of its own process. 4137e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // 2. Address space of the kernel. 4147e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 4157e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh uint64_t mapped_addr = 0; 4167e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 4177e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Sometimes the first event we see is a SAMPLE event and we don't have the 4187e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // time to create an address mapper for a process. Example, for pid 0. 4197e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh AddressMapper* mapper = GetOrCreateProcessMapper(pid).first; 4207e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh bool mapped = mapper->GetMappedAddress(ip, &mapped_addr); 4217e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (!mapped) { 4227e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh mapper = kernel_mapper_.get(); 4237e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh mapped = mapper->GetMappedAddress(ip, &mapped_addr); 4247e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 4257e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 4267e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // TODO(asharif): What should we do when we cannot map a SAMPLE event? 4277e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (mapped) { 4287e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (dso_and_offset) { 4297e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh uint64_t id = kuint64max; 4307e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh CHECK(mapper->GetMappedIDAndOffset(ip, &id, &dso_and_offset->offset_)); 4317e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Make sure the ID points to a valid event. 4327e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh CHECK_LE(id, parsed_events_sorted_by_time_.size()); 4337e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh ParsedEvent* parsed_event = parsed_events_sorted_by_time_[id]; 4347e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh const event_t* raw_event = parsed_event->raw_event; 4357e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 4367e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh DSOInfo dso_info; 4377e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (raw_event->header.type == PERF_RECORD_MMAP) { 4387e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh dso_info.name = raw_event->mmap.filename; 4397e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } else if (raw_event->header.type == PERF_RECORD_MMAP2) { 4407e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh dso_info.name = raw_event->mmap2.filename; 4417e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } else { 4427e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh LOG(FATAL) << "Expected MMAP or MMAP2 event"; 4437e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 4447e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 4457e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // Find the mmap DSO filename in the set of known DSO names. 4467e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // TODO(sque): take build IDs into account. 4477e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh std::set<DSOInfo>::const_iterator dso_iter = dso_set_.find(dso_info); 4487e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh CHECK(dso_iter != dso_set_.end()); 4497e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh dso_and_offset->dso_info_ = &(*dso_iter); 4507e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 4517e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh ++parsed_event->num_samples_in_mmap_region; 4527e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 4537e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (options_.do_remap) 4547e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh *new_ip = mapped_addr; 4557e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 4567e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return mapped; 4577e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh} 4587e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 4597e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshbool PerfParser::MapMmapEvent(uint64_t id, 4607e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh uint32_t pid, 4617e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh uint64_t* p_start, 4627e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh uint64_t* p_len, 4637e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh uint64_t* p_pgoff) 4647e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh{ 4657e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // We need to hide only the real kernel addresses. However, to make things 4667e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // more secure, and make the mapping idempotent, we should remap all 4677e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // addresses, both kernel and non-kernel. 4687e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh AddressMapper* mapper = 4697e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh (pid == kKernelPid ? kernel_mapper_.get() : 4707e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh GetOrCreateProcessMapper(pid).first); 4717e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 4727e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh uint64_t start = *p_start; 4737e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh uint64_t len = *p_len; 4747e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh uint64_t pgoff = *p_pgoff; 4757e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 4767e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // |id| == 0 corresponds to the kernel mmap. We have several cases here: 4777e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // 4787e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // For ARM and x86, in sudo mode, pgoff == start, example: 4797e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // start=0x80008200 4807e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // pgoff=0x80008200 4817e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // len =0xfffffff7ff7dff 4827e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // 4837e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // For x86-64, in sudo mode, pgoff is between start and start + len. SAMPLE 4847e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // events lie between pgoff and pgoff + length of the real kernel binary, 4857e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // example: 4867e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // start=0x3bc00000 4877e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // pgoff=0xffffffffbcc00198 4887e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // len =0xffffffff843fffff 4897e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // SAMPLE events will be found after pgoff. For kernels with ASLR, pgoff will 4907e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // be something only visible to the root user, and will be randomized at 4917e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // startup. With |remap| set to true, we should hide pgoff in this case. So we 4927e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // normalize all SAMPLE events relative to pgoff. 4937e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // 4947e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // For non-sudo mode, the kernel will be mapped from 0 to the pointer limit, 4957e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // example: 4967e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // start=0x0 4977e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // pgoff=0x0 4987e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // len =0xffffffff 4997e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (id == 0) { 5007e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // If pgoff is between start and len, we normalize the event by setting 5017e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // start to be pgoff just like how it is for ARM and x86. We also set len to 5027e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // be a much smaller number (closer to the real length of the kernel binary) 5037e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // because SAMPLEs are actually only seen between |event->pgoff| and 5047e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // |event->pgoff + kernel text size|. 5057e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (pgoff > start && pgoff < start + len) { 5067e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh len = len + start - pgoff; 5077e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh start = pgoff; 5087e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 5097e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // For kernels with ALSR pgoff is critical information that should not be 5107e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // revealed when |remap| is true. 5117e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh pgoff = 0; 5127e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 5137e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 5147e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (!mapper->MapWithID(start, len, id, pgoff, true)) { 5157e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh mapper->DumpToLog(); 5167e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return false; 5177e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 5187e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 5197e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (options_.do_remap) { 5207e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh uint64_t mapped_addr; 5217e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh CHECK(mapper->GetMappedAddress(start, &mapped_addr)); 5227e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh *p_start = mapped_addr; 5237e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh *p_len = len; 5247e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh *p_pgoff = pgoff; 5257e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 5267e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return true; 5277e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh} 5287e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 5297e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshstd::pair<AddressMapper*, bool> PerfParser::GetOrCreateProcessMapper( 5307e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh uint32_t pid, uint32_t *ppid) { 5317e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh const auto& search = process_mappers_.find(pid); 5327e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (search != process_mappers_.end()) { 5337e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return std::make_pair(search->second.get(), false); 5347e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 5357e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 5367e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh std::unique_ptr<AddressMapper> mapper; 5377e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh const auto& parent_mapper = (ppid ? process_mappers_.find(*ppid) : process_mappers_.end()); 5387e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (parent_mapper != process_mappers_.end()) 5397e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh mapper.reset(new AddressMapper(*parent_mapper->second)); 5407e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh else 5417e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh mapper.reset(new AddressMapper()); 5427e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 5437e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh const auto inserted = 5447e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh process_mappers_.insert(search, std::make_pair(pid, std::move(mapper))); 5457e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return std::make_pair(inserted->second.get(), true); 5467e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh} 5477e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 5487e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshbool PerfParser::MapCommEvent(const struct comm_event& event) { 5497e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh GetOrCreateProcessMapper(event.pid); 5507e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return true; 5517e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh} 5527e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 5537e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntoshbool PerfParser::MapForkEvent(const struct fork_event& event) { 5547e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh PidTid parent = std::make_pair(event.ppid, event.ptid); 5557e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh PidTid child = std::make_pair(event.pid, event.tid); 5567e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (parent != child && 5577e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh pidtid_to_comm_map_.find(parent) != pidtid_to_comm_map_.end()) { 5587e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh pidtid_to_comm_map_[child] = pidtid_to_comm_map_[parent]; 5597e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 5607e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 5617e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh const uint32_t pid = event.pid; 5627e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 5637e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // If the parent and child pids are the same, this is just a new thread 5647e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh // within the same process, so don't do anything. 5657e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (event.ppid == pid) 5667e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return true; 5677e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 5687e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh uint32_t ppid = event.ppid; 5697e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh if (!GetOrCreateProcessMapper(pid, &ppid).second) { 5707e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh DLOG(INFO) << "Found an existing process mapper with pid: " << pid; 5717e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh } 5727e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 5737e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh return true; 5747e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh} 5757e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh 5767e2f4e9d384d501cf86118ebac4b8de2b86eac53Than McIntosh} // namespace quipper 577