Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (c) 2016, Google Inc.
      3  * All rights reserved.
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "perf_data_converter.h"
      9 
     10 #include <algorithm>
     11 #include <deque>
     12 #include <map>
     13 #include <sstream>
     14 #include <vector>
     15 
     16 #include "int_compat.h"
     17 #include "perf_data_handler.h"
     18 #include "string_compat.h"
     19 #include "builder.h"
     20 #include "quipper/perf_data.pb.h"
     21 #include "quipper/perf_parser.h"
     22 #include "quipper/perf_reader.h"
     23 
     24 namespace perftools {
     25 namespace {
     26 
     27 typedef perftools::profiles::Profile Profile;
     28 typedef perftools::profiles::Builder ProfileBuilder;
     29 
     30 typedef uint32 Pid;
     31 
     32 enum ExecutionMode {
     33   Unknown,
     34   HostKernel,
     35   HostUser,
     36   GuestKernel,
     37   GuestUser,
     38   Hypervisor
     39 };
     40 
     41 const char* ExecModeString(ExecutionMode mode) {
     42   switch (mode) {
     43     case HostKernel:
     44       return ExecutionModeHostKernel;
     45     case HostUser:
     46       return ExecutionModeHostUser;
     47     case GuestKernel:
     48       return ExecutionModeGuestKernel;
     49     case GuestUser:
     50       return ExecutionModeGuestUser;
     51     case Hypervisor:
     52       return ExecutionModeHypervisor;
     53     default:
     54       std::cerr << "Execution mode not handled: " << mode << std::endl;
     55       return "";
     56   }
     57 }
     58 
     59 ExecutionMode PerfExecMode(const PerfDataHandler::SampleContext& sample) {
     60   if (sample.header.has_misc()) {
     61     switch (sample.header.misc() & PERF_RECORD_MISC_CPUMODE_MASK) {
     62       case PERF_RECORD_MISC_KERNEL:
     63         return HostKernel;
     64       case PERF_RECORD_MISC_USER:
     65         return HostUser;
     66       case PERF_RECORD_MISC_GUEST_KERNEL:
     67         return GuestKernel;
     68       case PERF_RECORD_MISC_GUEST_USER:
     69         return GuestUser;
     70       case PERF_RECORD_MISC_HYPERVISOR:
     71         return Hypervisor;
     72     }
     73   }
     74   return Unknown;
     75 }
     76 
     77 // Adds the string to the profile builder. If the UTF-8 library is included,
     78 // this also ensures the string contains structurally valid UTF-8.
     79 // In order to successfully unmarshal the proto in Go, all strings inserted into
     80 // the profile string table must be valid UTF-8.
     81 int64 UTF8StringId(const string& s, ProfileBuilder* builder) {
     82   return builder->StringId(s.c_str());
     83 }
     84 
     85 // Returns the file name of the mapping as either the real file path if it's
     86 // present or the string representation of the file path MD5 checksum prefix
     87 // when the real file path was stripped from the data for privacy reasons.
     88 string MappingFilename(const PerfDataHandler::Mapping* m) {
     89   if (m->filename != nullptr && !m->filename->empty()) {
     90     return *m->filename;
     91   } else if (m->filename_md5_prefix != 0) {
     92     std::stringstream filename;
     93     filename << std::hex << m->filename_md5_prefix;
     94     return filename.str();
     95   }
     96   return "";
     97 }
     98 
     99 // List of profile location IDs, currently used to represent a call stack.
    100 typedef std::vector<uint64> LocationIdVector;
    101 
    102 // It is sufficient to key the location and mapping maps by PID.
    103 // However, when Samples include labels, it is necessary to key their maps
    104 // not only by PID, but also by anything their labels may contain, since labels
    105 // are also distinguishing features.  This struct should contain everything
    106 // required to uniquely identify a Sample: if two Samples you consider different
    107 // end up with the same SampleKey, you should extend SampleKey til they don't.
    108 //
    109 // If any of these values are not used as labels, they should be set to 0.
    110 struct SampleKey {
    111   Pid pid = 0;
    112   Pid tid = 0;
    113   uint64 time_ns = 0;
    114   ExecutionMode exec_mode = Unknown;
    115   // The index of the sample's command in the profile's string table.
    116   uint64 comm = 0;
    117   LocationIdVector stack;
    118 };
    119 
    120 struct SampleKeyEqualityTester {
    121   bool operator()(const SampleKey a, const SampleKey b) const {
    122     return ((a.pid == b.pid) && (a.tid == b.tid) && (a.time_ns == b.time_ns) &&
    123             (a.exec_mode == b.exec_mode) && (a.comm == b.comm) &&
    124             (a.stack == b.stack));
    125   }
    126 };
    127 
    128 struct SampleKeyHasher {
    129   size_t operator()(const SampleKey k) const {
    130     size_t hash = 0;
    131     hash ^= std::hash<int32>()(k.pid);
    132     hash ^= std::hash<int32>()(k.tid);
    133     hash ^= std::hash<uint64>()(k.time_ns);
    134     hash ^= std::hash<int>()(k.exec_mode);
    135     hash ^= std::hash<uint64>()(k.comm);
    136     for (const auto& id : k.stack) {
    137       hash ^= std::hash<uint64>()(id);
    138     }
    139     return hash;
    140   }
    141 };
    142 
    143 // While Locations and Mappings are per-address-space (=per-process), samples
    144 // can be thread-specific.  If the requested sample labels include PID and
    145 // TID, we'll need to maintain separate profile sample objects for samples
    146 // that are identical except for TID.  Likewise, if the requested sample
    147 // labels include timestamp_ns, then we'll need to have separate
    148 // profile_proto::Samples for samples that are identical except for timestamp.
    149 typedef std::unordered_map<SampleKey, perftools::profiles::Sample*,
    150                            SampleKeyHasher, SampleKeyEqualityTester> SampleMap;
    151 
    152 // Map from a virtual address to a profile location ID. It only keys off the
    153 // address, not also the mapping ID since the map / its portions are invalidated
    154 // by Comm() and MMap() methods to force re-creation of those locations.
    155 //
    156 typedef std::map<uint64, uint64> LocationMap;
    157 
    158 // Map from the handler mapping object to profile mapping ID. The mappings
    159 // the handler creates are immutable and reasonably shared (as in no new mapping
    160 // object is created per, say, each sample), so using the pointers is OK.
    161 typedef std::unordered_map<const PerfDataHandler::Mapping*, uint64> MappingMap;
    162 
    163 // Per-process (aggregated when no PID grouping requested) info.
    164 // See docs on ProcessProfile in the header file for details on the fields.
    165 class ProcessMeta {
    166  public:
    167   // Constructs the object for the specified PID.
    168   explicit ProcessMeta(Pid pid) : pid_(pid) {}
    169 
    170   // Updates the bounding time interval ranges per specified timestamp.
    171   void UpdateTimestamps(int64 time_nsec) {
    172     if (min_sample_time_ns_ == 0 || time_nsec < min_sample_time_ns_) {
    173       min_sample_time_ns_ = time_nsec;
    174     }
    175     if (max_sample_time_ns_ == 0 || time_nsec > max_sample_time_ns_) {
    176       max_sample_time_ns_ = time_nsec;
    177     }
    178   }
    179 
    180   std::unique_ptr<ProcessProfile> makeProcessProfile(Profile* data) {
    181     ProcessProfile* pp = new ProcessProfile();
    182     pp->pid = pid_;
    183     pp->data.Swap(data);
    184     pp->min_sample_time_ns = min_sample_time_ns_;
    185     pp->max_sample_time_ns = max_sample_time_ns_;
    186     return std::unique_ptr<ProcessProfile>(pp);
    187   }
    188 
    189  private:
    190   Pid pid_;
    191   int64 min_sample_time_ns_ = 0;
    192   int64 max_sample_time_ns_ = 0;
    193 };
    194 
    195 class PerfDataConverter : public PerfDataHandler {
    196  public:
    197   explicit PerfDataConverter(const quipper::PerfDataProto& perf_data,
    198                              uint32 sample_labels = kNoLabels,
    199                              uint32 options = kGroupByPids)
    200       : perf_data_(perf_data),
    201         sample_labels_(sample_labels),
    202         options_(options) {}
    203   PerfDataConverter(const PerfDataConverter&) = delete;
    204   PerfDataConverter& operator=(const PerfDataConverter&) = delete;
    205   virtual ~PerfDataConverter() {}
    206 
    207   ProcessProfiles Profiles();
    208 
    209   // Callbacks for PerfDataHandler
    210   void Sample(const PerfDataHandler::SampleContext& sample) override;
    211   void Comm(const CommContext& comm) override;
    212   void MMap(const MMapContext& mmap) override;
    213 
    214  private:
    215   // Adds a new sample updating the event counters if such sample is not present
    216   // in the profile initializing its metrics. Updates the metrics associated
    217   // with the sample if the sample was added before.
    218   void AddOrUpdateSample(const PerfDataHandler::SampleContext& context,
    219                          const Pid& pid, const SampleKey& sample_key,
    220                          ProfileBuilder* builder);
    221 
    222   // Adds a new location to the profile if such location is not present in the
    223   // profile, returning the ID of the location. It also adds the profile mapping
    224   // corresponding to the specified handler mapping.
    225   uint64 AddOrGetLocation(const Pid& pid, uint64 addr,
    226                           const PerfDataHandler::Mapping* mapping,
    227                           ProfileBuilder* builder);
    228 
    229   // Adds a new mapping to the profile if such mapping is not present in the
    230   // profile, returning the ID of the mapping. It returns 0 to indicate that the
    231   // mapping was not added (only happens if smap == 0 currently).
    232   uint64 AddOrGetMapping(const Pid& pid, const PerfDataHandler::Mapping* smap,
    233                          ProfileBuilder* builder);
    234 
    235   // Returns whether pid labels were requested for inclusion in the
    236   // profile.proto's Sample.Label field.
    237   bool IncludePidLabels() const { return (sample_labels_ & kPidLabel); }
    238   // Returns whether tid labels were requested for inclusion in the
    239   // profile.proto's Sample.Label field.
    240   bool IncludeTidLabels() const { return (sample_labels_ & kTidLabel); }
    241   // Returns whether timestamp_ns labels were requested for inclusion in the
    242   // profile.proto's Sample.Label field.
    243   bool IncludeTimestampNsLabels() const {
    244     return (sample_labels_ & kTimestampNsLabel);
    245   }
    246   // Returns whether execution_mode labels were requested for inclusion in the
    247   // profile.proto's Sample.Label field.
    248   bool IncludeExecutionModeLabels() const {
    249     return (sample_labels_ & kExecutionModeLabel);
    250   }
    251   // Returns whether comm labels were requested for inclusion in the
    252   // profile.proto's Sample.Label field.
    253   bool IncludeCommLabels() const { return (sample_labels_ & kCommLabel); }
    254 
    255   SampleKey MakeSampleKey(const PerfDataHandler::SampleContext& sample,
    256                           ProfileBuilder* builder);
    257 
    258   ProfileBuilder* GetOrCreateBuilder(
    259       const PerfDataHandler::SampleContext& sample);
    260 
    261   const quipper::PerfDataProto& perf_data_;
    262   // Using deque so that appends do not invalidate existing pointers.
    263   std::deque<ProfileBuilder> builders_;
    264   std::deque<ProcessMeta> process_metas_;
    265 
    266   struct PerPidInfo {
    267     ProfileBuilder* builder = nullptr;
    268     ProcessMeta* process_meta = nullptr;
    269     LocationMap location_map;
    270     MappingMap mapping_map;
    271     std::unordered_map<Pid, string> tid_to_comm_map;
    272     SampleMap sample_map;
    273     void clear() {
    274       builder = nullptr;
    275       process_meta = nullptr;
    276       location_map.clear();
    277       mapping_map.clear();
    278       tid_to_comm_map.clear();
    279       sample_map.clear();
    280     }
    281   };
    282   std::unordered_map<Pid, PerPidInfo> per_pid_;
    283 
    284   const uint32 sample_labels_;
    285   const uint32 options_;
    286 };
    287 
    288 SampleKey PerfDataConverter::MakeSampleKey(
    289     const PerfDataHandler::SampleContext& sample, ProfileBuilder* builder) {
    290   SampleKey sample_key;
    291   sample_key.pid = sample.sample.has_pid() ? sample.sample.pid() : 0;
    292   sample_key.tid =
    293       (IncludeTidLabels() && sample.sample.has_tid()) ? sample.sample.tid() : 0;
    294   sample_key.time_ns =
    295       (IncludeTimestampNsLabels() && sample.sample.has_sample_time_ns())
    296           ? sample.sample.sample_time_ns()
    297           : 0;
    298   if (IncludeExecutionModeLabels()) {
    299     sample_key.exec_mode = PerfExecMode(sample);
    300   }
    301   if (IncludeCommLabels() && sample.sample.has_pid() &&
    302       sample.sample.has_tid()) {
    303     Pid pid = sample.sample.pid();
    304     Pid tid = sample.sample.tid();
    305     const string& comm = per_pid_[pid].tid_to_comm_map[tid];
    306     if (!comm.empty()) {
    307       sample_key.comm = UTF8StringId(comm, builder);
    308     }
    309   }
    310   return sample_key;
    311 }
    312 
    313 ProfileBuilder* PerfDataConverter::GetOrCreateBuilder(
    314     const PerfDataHandler::SampleContext& sample) {
    315   Pid builder_pid = (options_ & kGroupByPids) ? sample.sample.pid() : 0;
    316   auto& per_pid = per_pid_[builder_pid];
    317   if (per_pid.builder == nullptr) {
    318     builders_.push_back(ProfileBuilder());
    319     per_pid.builder = &builders_.back();
    320     process_metas_.push_back(ProcessMeta(builder_pid));
    321     per_pid.process_meta = &process_metas_.back();
    322 
    323     ProfileBuilder* builder = per_pid.builder;
    324     Profile* profile = builder->mutable_profile();
    325     int unknown_event_idx = 0;
    326     for (int event_idx = 0; event_idx < perf_data_.file_attrs_size();
    327          ++event_idx) {
    328       // Come up with an event name for this event.  perf.data will usually
    329       // contain an event_types section of the same cardinality as its
    330       // file_attrs; in this case we can just use the name there.  Otherwise
    331       // we just give it an anonymous name.
    332       string event_name = "";
    333       if (perf_data_.file_attrs_size() == perf_data_.event_types_size()) {
    334         const auto& event_type = perf_data_.event_types(event_idx);
    335         if (event_type.has_name()) {
    336           event_name = event_type.name() + "_";
    337         }
    338       }
    339       if (event_name == "") {
    340         event_name = "event_" + std::to_string(unknown_event_idx++) + "_";
    341       }
    342       auto sample_type = profile->add_sample_type();
    343       sample_type->set_type(UTF8StringId(event_name + "sample", builder));
    344       sample_type->set_unit(builder->StringId("count"));
    345       sample_type = profile->add_sample_type();
    346       sample_type->set_type(UTF8StringId(event_name + "event", builder));
    347       sample_type->set_unit(builder->StringId("count"));
    348     }
    349     if (sample.main_mapping == nullptr) {
    350       auto fake_main = profile->add_mapping();
    351       fake_main->set_id(profile->mapping_size());
    352       fake_main->set_memory_start(0);
    353       fake_main->set_memory_limit(1);
    354     } else {
    355       AddOrGetMapping(sample.sample.pid(), sample.main_mapping, builder);
    356     }
    357     if (perf_data_.string_metadata().has_perf_version()) {
    358       string perf_version =
    359           "perf-version:" + perf_data_.string_metadata().perf_version().value();
    360       profile->add_comment(UTF8StringId(perf_version, builder));
    361     }
    362     if (perf_data_.string_metadata().has_perf_command_line_whole()) {
    363       string perf_command =
    364           "perf-command:" +
    365           perf_data_.string_metadata().perf_command_line_whole().value();
    366       profile->add_comment(UTF8StringId(perf_command, builder));
    367     }
    368   } else {
    369     Profile* profile = per_pid.builder->mutable_profile();
    370     if ((options_ & kGroupByPids) && sample.main_mapping != nullptr &&
    371         sample.main_mapping->filename != nullptr) {
    372       const string& filename =
    373           profile->string_table(profile->mapping(0).filename());
    374       const string& sample_filename = MappingFilename(sample.main_mapping);
    375 
    376       if (filename != sample_filename) {
    377         if (options_ & kFailOnMainMappingMismatch) {
    378           LOG(FATAL) << "main mapping mismatch: " << sample.sample.pid() << " "
    379                      << filename << " " << sample_filename;
    380         } else {
    381           LOG(WARNING) << "main mapping mismatch: " << sample.sample.pid()
    382                        << " " << filename << " " << sample_filename;
    383         }
    384       }
    385     }
    386   }
    387   if (sample.sample.sample_time_ns()) {
    388     per_pid.process_meta->UpdateTimestamps(sample.sample.sample_time_ns());
    389   }
    390   return per_pid.builder;
    391 }
    392 
    393 uint64 PerfDataConverter::AddOrGetMapping(const Pid& pid,
    394                                           const PerfDataHandler::Mapping* smap,
    395                                           ProfileBuilder* builder) {
    396   if (builder == nullptr) {
    397     std::cerr << "Cannot add mapping to null builder." << std::endl;
    398     abort();
    399   }
    400 
    401   if (smap == nullptr) {
    402     return 0;
    403   }
    404 
    405   MappingMap& mapmap = per_pid_[pid].mapping_map;
    406   auto it = mapmap.find(smap);
    407   if (it != mapmap.end()) {
    408     return it->second;
    409   }
    410 
    411   Profile* profile = builder->mutable_profile();
    412   auto mapping = profile->add_mapping();
    413   uint64 mapping_id = profile->mapping_size();
    414   mapping->set_id(mapping_id);
    415   mapping->set_memory_start(smap->start);
    416   mapping->set_memory_limit(smap->limit);
    417   mapping->set_file_offset(smap->file_offset);
    418   if (smap->build_id != nullptr && !smap->build_id->empty()) {
    419     mapping->set_build_id(UTF8StringId(*smap->build_id, builder));
    420   }
    421   mapping->set_filename(UTF8StringId(MappingFilename(smap), builder));
    422   if (mapping->memory_start() >= mapping->memory_limit()) {
    423     std::cerr << "The start of the mapping must be strictly less than its"
    424               << "limit in file: " << mapping->filename() << std::endl
    425               << "Start: " << mapping->memory_start() << std::endl
    426               << "Limit: " << mapping->memory_limit() << std::endl;
    427     abort();
    428   }
    429   mapmap.insert(std::make_pair(smap, mapping_id));
    430   return mapping_id;
    431 }
    432 
    433 void PerfDataConverter::AddOrUpdateSample(
    434     const PerfDataHandler::SampleContext& context, const Pid& pid,
    435     const SampleKey& sample_key,
    436     ProfileBuilder* builder) {
    437 
    438   perftools::profiles::Sample* sample = per_pid_[pid].sample_map[sample_key];
    439 
    440   if (sample == nullptr) {
    441     Profile* profile = builder->mutable_profile();
    442     sample = profile->add_sample();
    443     per_pid_[pid].sample_map[sample_key] = sample;
    444     for (const auto& location_id : sample_key.stack) {
    445       sample->add_location_id(location_id);
    446     }
    447     // Emit any requested labels.
    448     if (IncludePidLabels() && context.sample.has_pid()) {
    449       auto* label = sample->add_label();
    450       label->set_key(builder->StringId(PidLabelKey));
    451       label->set_num(static_cast<int64>(context.sample.pid()));
    452     }
    453     if (IncludeTidLabels() && context.sample.has_tid()) {
    454       auto* label = sample->add_label();
    455       label->set_key(builder->StringId(TidLabelKey));
    456       label->set_num(static_cast<int64>(context.sample.tid()));
    457     }
    458     if (IncludeCommLabels() && sample_key.comm != 0) {
    459       auto* label = sample->add_label();
    460       label->set_key(builder->StringId(CommLabelKey));
    461       label->set_str(sample_key.comm);
    462     }
    463     if (IncludeTimestampNsLabels() && context.sample.has_sample_time_ns()) {
    464       auto* label = sample->add_label();
    465       label->set_key(builder->StringId(TimestampNsLabelKey));
    466       int64 timestamp_ns_as_int64 =
    467           static_cast<int64>(context.sample.sample_time_ns());
    468       label->set_num(timestamp_ns_as_int64);
    469     }
    470     if (IncludeExecutionModeLabels() && sample_key.exec_mode != Unknown) {
    471       auto* label = sample->add_label();
    472       label->set_key(builder->StringId(ExecutionModeLabelKey));
    473       label->set_str(builder->StringId(ExecModeString(sample_key.exec_mode)));
    474     }
    475     // Two values per collected event: the first is sample counts, the second is
    476     // event counts (unsampled weight for each sample).
    477     for (int event_id = 0; event_id < perf_data_.file_attrs_size();
    478          ++event_id) {
    479       sample->add_value(0);
    480       sample->add_value(0);
    481     }
    482   }
    483 
    484   int64 weight = 1;
    485   // If the sample has a period, use that in preference
    486   if (context.sample.period() > 0) {
    487     weight = context.sample.period();
    488   } else if (context.file_attrs_index >= 0) {
    489     uint64 period =
    490         perf_data_.file_attrs(context.file_attrs_index).attr().sample_period();
    491     if (period > 0) {
    492       // If sampling used a fixed period, use that as the weight.
    493       weight = period;
    494     }
    495   }
    496   int event_index = context.file_attrs_index;
    497   sample->set_value(2 * event_index, sample->value(2 * event_index) + 1);
    498   sample->set_value(2 * event_index + 1,
    499                     sample->value(2 * event_index + 1) + weight);
    500 }
    501 
    502 uint64 PerfDataConverter::AddOrGetLocation(
    503     const Pid& pid, uint64 addr, const PerfDataHandler::Mapping* mapping,
    504     ProfileBuilder* builder) {
    505   LocationMap& loc_map = per_pid_[pid].location_map;
    506   auto loc_it = loc_map.find(addr);
    507   if (loc_it != loc_map.end()) {
    508     return loc_it->second;
    509   }
    510 
    511   Profile* profile = builder->mutable_profile();
    512   perftools::profiles::Location* loc = profile->add_location();
    513   uint64 loc_id = profile->location_size();
    514   loc->set_id(loc_id);
    515   loc->set_address(addr);
    516   uint64 mapping_id = AddOrGetMapping(pid, mapping, builder);
    517   if (mapping_id != 0) {
    518     loc->set_mapping_id(mapping_id);
    519   } else {
    520     if (addr != 0) {
    521       std::cerr << "Found unmapped address: " << addr << " in PID " << pid
    522                 << std::endl;
    523       abort();
    524     }
    525   }
    526   loc_map[addr] = loc_id;
    527   return loc_id;
    528 }
    529 
    530 void PerfDataConverter::Comm(const CommContext& comm) {
    531   Pid pid = comm.comm->pid();
    532   Pid tid = comm.comm->tid();
    533   if (pid == tid) {
    534     // pid==tid means an exec() happened, so clear everything from the
    535     // existing pid.
    536     per_pid_[pid].clear();
    537   }
    538 
    539   per_pid_[pid].tid_to_comm_map[tid] = comm.comm->comm();
    540 }
    541 
    542 // Invalidates the locations in location_map in the mmap event's range.
    543 void PerfDataConverter::MMap(const MMapContext& mmap) {
    544   LocationMap& loc_map = per_pid_[mmap.pid].location_map;
    545   loc_map.erase(loc_map.lower_bound(mmap.mapping->start),
    546                 loc_map.lower_bound(mmap.mapping->limit));
    547 }
    548 
    549 void PerfDataConverter::Sample(const PerfDataHandler::SampleContext& sample) {
    550   if (sample.file_attrs_index < 0 ||
    551       sample.file_attrs_index >= perf_data_.file_attrs_size()) {
    552     LOG(WARNING) << "out of bounds file_attrs_index: "
    553                  << sample.file_attrs_index;
    554     return;
    555   }
    556 
    557   Pid event_pid = sample.sample.pid();
    558   ProfileBuilder *builder = GetOrCreateBuilder(sample);
    559   SampleKey sample_key = MakeSampleKey(sample, builder);
    560 
    561   uint64 ip = sample.sample_mapping != nullptr ? sample.sample.ip() : 0;
    562   if (ip != 0) {
    563     const auto start = sample.sample_mapping->start;
    564     const auto limit = sample.sample_mapping->limit;
    565     if (ip < start || ip >= limit) {
    566       std::cerr << "IP is out of bound of mapping." << std::endl
    567                 << "IP: " << ip << std::endl
    568                 << "Start: " << start << std::endl
    569                 << "Limit: " << limit << std::endl;
    570     }
    571   }
    572 
    573   // Leaf at stack[0]
    574   sample_key.stack.push_back(
    575       AddOrGetLocation(event_pid, ip, sample.sample_mapping, builder));
    576 
    577   // LBR callstacks include only user call chains. If this is an LBR sample,
    578   // we get the kernel callstack from the sample's callchain, and the user
    579   // callstack from the sample's branch_stack.
    580   const bool lbr_sample = !sample.branch_stack.empty();
    581   bool skipped_dup = false;
    582   for (const auto& frame : sample.callchain) {
    583     if (lbr_sample && frame.ip == PERF_CONTEXT_USER) {
    584       break;
    585     }
    586     if (!skipped_dup && sample_key.stack.size() == 1 && frame.ip == ip) {
    587       skipped_dup = true;
    588       // Newer versions of perf_events include the IP at the leaf of
    589       // the callchain.
    590       continue;
    591     }
    592     if (frame.mapping == nullptr) {
    593       continue;
    594     }
    595     uint64 frame_ip = frame.ip;
    596     // Why <=? Because this is a return address, which should be
    597     // preceded by a call (the "real" context.)  If we're at the edge
    598     // of the mapping, we're really off its edge.
    599     if (frame_ip <= frame.mapping->start) {
    600       continue;
    601     }
    602     // these aren't real callchain entries, just hints as to kernel/user
    603     // addresses.
    604     if (frame_ip >= PERF_CONTEXT_MAX) {
    605       continue;
    606     }
    607 
    608     // subtract one so we point to the call instead of the return addr.
    609     frame_ip--;
    610     sample_key.stack.push_back(
    611         AddOrGetLocation(event_pid, frame_ip, frame.mapping, builder));
    612   }
    613   for (const auto& frame : sample.branch_stack) {
    614     // branch_stack entries are pairs of <from, to> locations corresponding to
    615     // addresses of call instructions and target addresses of those calls.
    616     // We need only the addresses of the function call instructions, stored in
    617     // the 'from' field, to recover the call chains.
    618     if (frame.from.mapping == nullptr) {
    619       continue;
    620     }
    621     // An LBR entry includes the address of the call instruction, so we don't
    622     // have to do any adjustments.
    623     if (frame.from.ip < frame.from.mapping->start) {
    624       continue;
    625     }
    626     sample_key.stack.push_back(AddOrGetLocation(event_pid, frame.from.ip,
    627                                                 frame.from.mapping, builder));
    628   }
    629   AddOrUpdateSample(sample, event_pid, sample_key, builder);
    630 }
    631 
    632 ProcessProfiles PerfDataConverter::Profiles() {
    633   ProcessProfiles pps;
    634   for (int i = 0; i < builders_.size(); i++) {
    635     auto& b = builders_[i];
    636     b.Finalize();
    637     auto pp = process_metas_[i].makeProcessProfile(b.mutable_profile());
    638     pps.push_back(std::move(pp));
    639   }
    640   return pps;
    641 }
    642 
    643 }  // namespace
    644 
    645 ProcessProfiles PerfDataProtoToProfiles(const quipper::PerfDataProto* perf_data,
    646                                         const uint32 sample_labels,
    647                                         const uint32 options) {
    648   PerfDataConverter converter(*perf_data, sample_labels, options);
    649   PerfDataHandler::Process(*perf_data, &converter);
    650   return converter.Profiles();
    651 }
    652 
    653 ProcessProfiles RawPerfDataToProfiles(const void* raw, const int raw_size,
    654                                       const std::map<string, string>& build_ids,
    655                                       const uint32 sample_labels,
    656                                       const uint32 options) {
    657   quipper::PerfReader reader;
    658   if (!reader.ReadFromPointer(reinterpret_cast<const char*>(raw), raw_size)) {
    659     LOG(ERROR) << "Could not read input perf.data";
    660     return ProcessProfiles();
    661   }
    662 
    663   reader.InjectBuildIDs(build_ids);
    664   // Perf populates info about the kernel using multiple pathways,
    665   // which don't actually all match up how they name kernel data; in
    666   // particular, buildids are reported by a different name than the
    667   // actual "mmap" info.  Normalize these names so our ProcessProfiles
    668   // will match kernel mappings to a buildid.
    669   reader.LocalizeUsingFilenames({
    670       {"[kernel.kallsyms]_text", "[kernel.kallsyms]"},
    671       {"[kernel.kallsyms]_stext", "[kernel.kallsyms]"},
    672   });
    673 
    674   // Use PerfParser to modify reader's events to have magic done to them such
    675   // as hugepage deduction and sorting events based on time, if timestamps are
    676   // present.
    677   quipper::PerfParserOptions opts;
    678   opts.sort_events_by_time = true;
    679   opts.deduce_huge_page_mappings = true;
    680   opts.combine_mappings = true;
    681   quipper::PerfParser parser(&reader, opts);
    682   if (!parser.ParseRawEvents()) {
    683     LOG(ERROR) << "Could not parse perf events.";
    684     return ProcessProfiles();
    685   }
    686 
    687   return PerfDataProtoToProfiles(&reader.proto(), sample_labels, options);
    688 }
    689 
    690 }  // namespace perftools
    691