Home | History | Annotate | Download | only in quipper
      1 // Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "perf_serializer.h"
      6 
      7 #include <stdint.h>
      8 #include <stdio.h>
      9 #include <sys/time.h>
     10 
     11 #include <algorithm>  // for std::copy
     12 
     13 #include "base/logging.h"
     14 
     15 #include "binary_data_utils.h"
     16 #include "compat/proto.h"
     17 #include "compat/string.h"
     18 #include "kernel/perf_event.h"
     19 #include "perf_data_structures.h"
     20 #include "perf_data_utils.h"
     21 #include "perf_parser.h"
     22 #include "perf_reader.h"
     23 
     24 namespace quipper {
     25 
     26 PerfSerializer::PerfSerializer() {}
     27 
     28 PerfSerializer::~PerfSerializer() {}
     29 
     30 bool PerfSerializer::SerializePerfFileAttr(
     31     const PerfFileAttr& perf_file_attr,
     32     PerfDataProto_PerfFileAttr* perf_file_attr_proto) const {
     33   if (!SerializePerfEventAttr(perf_file_attr.attr,
     34                               perf_file_attr_proto->mutable_attr())) {
     35     return false;
     36   }
     37 
     38   for (size_t i = 0; i < perf_file_attr.ids.size(); i++)
     39     perf_file_attr_proto->add_ids(perf_file_attr.ids[i]);
     40   return true;
     41 }
     42 
     43 bool PerfSerializer::DeserializePerfFileAttr(
     44     const PerfDataProto_PerfFileAttr& perf_file_attr_proto,
     45     PerfFileAttr* perf_file_attr) const {
     46   if (!DeserializePerfEventAttr(perf_file_attr_proto.attr(),
     47                                 &perf_file_attr->attr)) {
     48     return false;
     49   }
     50 
     51   for (int i = 0; i < perf_file_attr_proto.ids_size(); i++)
     52     perf_file_attr->ids.push_back(perf_file_attr_proto.ids(i));
     53   return true;
     54 }
     55 
     56 bool PerfSerializer::SerializePerfEventAttr(
     57     const perf_event_attr& perf_event_attr,
     58     PerfDataProto_PerfEventAttr* perf_event_attr_proto) const {
     59 #define S(x) perf_event_attr_proto->set_##x(perf_event_attr.x)
     60   S(type);
     61   S(size);
     62   S(config);
     63   if (perf_event_attr_proto->freq())
     64     S(sample_freq);
     65   else
     66     S(sample_period);
     67   S(sample_type);
     68   S(read_format);
     69   S(disabled);
     70   S(inherit);
     71   S(pinned);
     72   S(exclusive);
     73   S(exclude_user);
     74   S(exclude_kernel);
     75   S(exclude_hv);
     76   S(exclude_idle);
     77   S(mmap);
     78   S(comm);
     79   S(freq);
     80   S(inherit_stat);
     81   S(enable_on_exec);
     82   S(task);
     83   S(watermark);
     84   S(precise_ip);
     85   S(mmap_data);
     86   S(sample_id_all);
     87   S(exclude_host);
     88   S(exclude_guest);
     89   S(exclude_callchain_kernel);
     90   S(exclude_callchain_user);
     91   S(mmap2);
     92   S(comm_exec);
     93   if (perf_event_attr_proto->watermark())
     94     S(wakeup_watermark);
     95   else
     96     S(wakeup_events);
     97   S(bp_type);
     98   S(bp_addr);
     99   S(bp_len);
    100   S(branch_sample_type);
    101   S(sample_regs_user);
    102   S(sample_stack_user);
    103 #undef S
    104   return true;
    105 }
    106 
    107 bool PerfSerializer::DeserializePerfEventAttr(
    108     const PerfDataProto_PerfEventAttr& perf_event_attr_proto,
    109     perf_event_attr* perf_event_attr) const {
    110   memset(perf_event_attr, 0, sizeof(*perf_event_attr));
    111 #define S(x) perf_event_attr->x = perf_event_attr_proto.x()
    112   S(type);
    113   S(size);
    114   S(config);
    115   if (perf_event_attr->freq)
    116     S(sample_freq);
    117   else
    118     S(sample_period);
    119   S(sample_type);
    120   S(read_format);
    121   S(disabled);
    122   S(inherit);
    123   S(pinned);
    124   S(exclusive);
    125   S(exclude_user);
    126   S(exclude_kernel);
    127   S(exclude_hv);
    128   S(exclude_idle);
    129   S(mmap);
    130   S(comm);
    131   S(freq);
    132   S(inherit_stat);
    133   S(enable_on_exec);
    134   S(task);
    135   S(watermark);
    136   S(precise_ip);
    137   S(mmap_data);
    138   S(sample_id_all);
    139   S(exclude_host);
    140   S(exclude_guest);
    141   S(exclude_callchain_kernel);
    142   S(exclude_callchain_user);
    143   S(mmap2);
    144   S(comm_exec);
    145   if (perf_event_attr->watermark)
    146     S(wakeup_watermark);
    147   else
    148     S(wakeup_events);
    149   S(bp_type);
    150   S(bp_addr);
    151   S(bp_len);
    152   S(branch_sample_type);
    153   S(sample_regs_user);
    154   S(sample_stack_user);
    155 #undef S
    156   return true;
    157 }
    158 
    159 bool PerfSerializer::SerializePerfEventType(
    160     const PerfFileAttr& event_attr,
    161     quipper::PerfDataProto_PerfEventType* event_type_proto) const {
    162   event_type_proto->set_id(event_attr.attr.config);
    163   event_type_proto->set_name(event_attr.name);
    164   event_type_proto->set_name_md5_prefix(Md5Prefix(event_attr.name));
    165   return true;
    166 }
    167 
    168 bool PerfSerializer::DeserializePerfEventType(
    169     const quipper::PerfDataProto_PerfEventType& event_type_proto,
    170     PerfFileAttr* event_attr) const {
    171   // Attr should have already been deserialized.
    172   if (event_attr->attr.config != event_type_proto.id()) {
    173     LOG(ERROR) << "Event type ID " << event_type_proto.id()
    174                << " does not match attr.config " << event_attr->attr.config
    175                << ". Not deserializing the event name!";
    176     return false;
    177   }
    178   event_attr->name = event_type_proto.name();
    179   return true;
    180 }
    181 
    182 bool PerfSerializer::SerializeEvent(
    183     const malloced_unique_ptr<event_t>& event_ptr,
    184     PerfDataProto_PerfEvent* event_proto) const {
    185   const event_t& event = *event_ptr;
    186 
    187   if (!SerializeEventHeader(event.header, event_proto->mutable_header()))
    188     return false;
    189 
    190   if (event.header.type >= PERF_RECORD_USER_TYPE_START) {
    191     if (!SerializeUserEvent(event, event_proto)) {
    192       return false;
    193     }
    194   } else if (!SerializeKernelEvent(event, event_proto)) {
    195     return false;
    196   }
    197 
    198   event_proto->set_timestamp(GetTimeFromPerfEvent(*event_proto));
    199   return true;
    200 }
    201 
    202 bool PerfSerializer::SerializeKernelEvent(
    203     const event_t& event, PerfDataProto_PerfEvent* event_proto) const {
    204   switch (event.header.type) {
    205     case PERF_RECORD_SAMPLE:
    206       return SerializeSampleEvent(event, event_proto->mutable_sample_event());
    207     case PERF_RECORD_MMAP:
    208       return SerializeMMapEvent(event, event_proto->mutable_mmap_event());
    209     case PERF_RECORD_MMAP2:
    210       return SerializeMMap2Event(event, event_proto->mutable_mmap_event());
    211     case PERF_RECORD_COMM:
    212       return SerializeCommEvent(event, event_proto->mutable_comm_event());
    213     case PERF_RECORD_EXIT:
    214       return SerializeForkExitEvent(event, event_proto->mutable_exit_event());
    215     case PERF_RECORD_FORK:
    216       return SerializeForkExitEvent(event, event_proto->mutable_fork_event());
    217     case PERF_RECORD_LOST:
    218       return SerializeLostEvent(event, event_proto->mutable_lost_event());
    219     case PERF_RECORD_THROTTLE:
    220     case PERF_RECORD_UNTHROTTLE:
    221       return SerializeThrottleEvent(event,
    222                                     event_proto->mutable_throttle_event());
    223     case PERF_RECORD_READ:
    224       return SerializeReadEvent(event, event_proto->mutable_read_event());
    225     case PERF_RECORD_AUX:
    226       return SerializeAuxEvent(event, event_proto->mutable_aux_event());
    227     default:
    228       LOG(ERROR) << "Unknown event type: " << event.header.type;
    229   }
    230   return true;
    231 }
    232 
    233 bool PerfSerializer::SerializeUserEvent(
    234     const event_t& event, PerfDataProto_PerfEvent* event_proto) const {
    235   switch (event.header.type) {
    236     case PERF_RECORD_AUXTRACE:
    237       return SerializeAuxtraceEvent(event,
    238                                     event_proto->mutable_auxtrace_event());
    239     default:
    240       if (event.header.type >= PERF_RECORD_HEADER_MAX) {
    241         LOG(ERROR) << "Unknown event type: " << event.header.type;
    242       }
    243   }
    244   return true;
    245 }
    246 
    247 bool PerfSerializer::DeserializeEvent(
    248     const PerfDataProto_PerfEvent& event_proto,
    249     malloced_unique_ptr<event_t>* event_ptr) const {
    250   event_ptr->reset(CallocMemoryForEvent(event_proto.header().size()));
    251   event_t* event = event_ptr->get();
    252 
    253   if (!DeserializeEventHeader(event_proto.header(), &event->header))
    254     return false;
    255 
    256   bool event_deserialized = false;
    257   if (event_proto.header().type() >= PERF_RECORD_USER_TYPE_START) {
    258     event_deserialized = DeserializeUserEvent(event_proto, event);
    259   } else {
    260     event_deserialized = DeserializeKernelEvent(event_proto, event);
    261   }
    262 
    263   if (!event_deserialized) {
    264     LOG(ERROR) << "Could not deserialize event of type "
    265                << event_proto.header().type();
    266     return false;
    267   }
    268 
    269   return true;
    270 }
    271 
    272 bool PerfSerializer::DeserializeKernelEvent(
    273     const PerfDataProto_PerfEvent& event_proto, event_t* event) const {
    274   switch (event_proto.header().type()) {
    275     case PERF_RECORD_SAMPLE:
    276       return DeserializeSampleEvent(event_proto.sample_event(), event);
    277     case PERF_RECORD_MMAP:
    278       return DeserializeMMapEvent(event_proto.mmap_event(), event);
    279     case PERF_RECORD_MMAP2:
    280       return DeserializeMMap2Event(event_proto.mmap_event(), event);
    281     case PERF_RECORD_COMM:
    282       return DeserializeCommEvent(event_proto.comm_event(), event);
    283     case PERF_RECORD_EXIT:
    284       return (event_proto.has_exit_event() &&
    285               DeserializeForkExitEvent(event_proto.exit_event(), event)) ||
    286              (event_proto.has_fork_event() &&
    287               DeserializeForkExitEvent(event_proto.fork_event(), event));
    288     // Some older protobufs use the |fork_event| field to store exit
    289     // events.
    290     case PERF_RECORD_FORK:
    291       return DeserializeForkExitEvent(event_proto.fork_event(), event);
    292     case PERF_RECORD_LOST:
    293       return DeserializeLostEvent(event_proto.lost_event(), event);
    294     case PERF_RECORD_THROTTLE:
    295     case PERF_RECORD_UNTHROTTLE:
    296       return DeserializeThrottleEvent(event_proto.throttle_event(), event);
    297     case PERF_RECORD_READ:
    298       return DeserializeReadEvent(event_proto.read_event(), event);
    299     case PERF_RECORD_AUX:
    300       return DeserializeAuxEvent(event_proto.aux_event(), event);
    301     case PERF_RECORD_ITRACE_START:
    302     case PERF_RECORD_LOST_SAMPLES:
    303     case PERF_RECORD_SWITCH:
    304     case PERF_RECORD_SWITCH_CPU_WIDE:
    305     case PERF_RECORD_NAMESPACES:
    306       LOG(ERROR) << "Event type: " << event_proto.header().type()
    307                  << ". Not yet supported.";
    308       return true;
    309       break;
    310   }
    311   return false;
    312 }
    313 
    314 bool PerfSerializer::DeserializeUserEvent(
    315     const PerfDataProto_PerfEvent& event_proto, event_t* event) const {
    316   switch (event_proto.header().type()) {
    317     case PERF_RECORD_AUXTRACE:
    318       return DeserializeAuxtraceEvent(event_proto.auxtrace_event(), event);
    319     default:
    320       // User type events are marked as deserialized because they don't
    321       // have non-header data in perf.data proto.
    322       if (event_proto.header().type() >= PERF_RECORD_HEADER_MAX) {
    323         return false;
    324       }
    325   }
    326   return true;
    327 }
    328 
    329 bool PerfSerializer::SerializeEventHeader(
    330     const perf_event_header& header,
    331     PerfDataProto_EventHeader* header_proto) const {
    332   header_proto->set_type(header.type);
    333   header_proto->set_misc(header.misc);
    334   header_proto->set_size(header.size);
    335   return true;
    336 }
    337 
    338 bool PerfSerializer::DeserializeEventHeader(
    339     const PerfDataProto_EventHeader& header_proto,
    340     perf_event_header* header) const {
    341   header->type = header_proto.type();
    342   header->misc = header_proto.misc();
    343   header->size = header_proto.size();
    344   return true;
    345 }
    346 
    347 bool PerfSerializer::SerializeSampleEvent(
    348     const event_t& event, PerfDataProto_SampleEvent* sample) const {
    349   perf_sample sample_info;
    350   uint64_t sample_type = 0;
    351   if (!ReadPerfSampleInfoAndType(event, &sample_info, &sample_type))
    352     return false;
    353 
    354   if (sample_type & PERF_SAMPLE_IP) sample->set_ip(sample_info.ip);
    355   if (sample_type & PERF_SAMPLE_TID) {
    356     sample->set_pid(sample_info.pid);
    357     sample->set_tid(sample_info.tid);
    358   }
    359   if (sample_type & PERF_SAMPLE_TIME)
    360     sample->set_sample_time_ns(sample_info.time);
    361   if (sample_type & PERF_SAMPLE_ADDR) sample->set_addr(sample_info.addr);
    362   if ((sample_type & PERF_SAMPLE_ID) || (sample_type & PERF_SAMPLE_IDENTIFIER))
    363     sample->set_id(sample_info.id);
    364   if (sample_type & PERF_SAMPLE_STREAM_ID)
    365     sample->set_stream_id(sample_info.stream_id);
    366   if (sample_type & PERF_SAMPLE_CPU) sample->set_cpu(sample_info.cpu);
    367   if (sample_type & PERF_SAMPLE_PERIOD) sample->set_period(sample_info.period);
    368   if (sample_type & PERF_SAMPLE_RAW) sample->set_raw_size(sample_info.raw_size);
    369   if (sample_type & PERF_SAMPLE_READ) {
    370     const SampleInfoReader* reader = GetSampleInfoReaderForEvent(event);
    371     if (reader) {
    372       PerfDataProto_ReadInfo* read_info = sample->mutable_read_info();
    373       if (reader->event_attr().read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
    374         read_info->set_time_enabled(sample_info.read.time_enabled);
    375       if (reader->event_attr().read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
    376         read_info->set_time_running(sample_info.read.time_running);
    377       if (reader->event_attr().read_format & PERF_FORMAT_GROUP) {
    378         for (size_t i = 0; i < sample_info.read.group.nr; i++) {
    379           auto read_value = read_info->add_read_value();
    380           read_value->set_value(sample_info.read.group.values[i].value);
    381           read_value->set_id(sample_info.read.group.values[i].id);
    382         }
    383       } else {
    384         auto read_value = read_info->add_read_value();
    385         read_value->set_value(sample_info.read.one.value);
    386         read_value->set_id(sample_info.read.one.id);
    387       }
    388     }
    389   }
    390   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
    391     sample->mutable_callchain()->Reserve(sample_info.callchain->nr);
    392     for (size_t i = 0; i < sample_info.callchain->nr; ++i)
    393       sample->add_callchain(sample_info.callchain->ips[i]);
    394   }
    395   if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
    396     for (size_t i = 0; i < sample_info.branch_stack->nr; ++i) {
    397       sample->add_branch_stack();
    398       const struct branch_entry& entry = sample_info.branch_stack->entries[i];
    399       sample->mutable_branch_stack(i)->set_from_ip(entry.from);
    400       sample->mutable_branch_stack(i)->set_to_ip(entry.to);
    401       sample->mutable_branch_stack(i)->set_mispredicted(entry.flags.mispred);
    402     }
    403   }
    404 
    405   if (sample_type & PERF_SAMPLE_WEIGHT) sample->set_weight(sample_info.weight);
    406   if (sample_type & PERF_SAMPLE_DATA_SRC)
    407     sample->set_data_src(sample_info.data_src);
    408   if (sample_type & PERF_SAMPLE_TRANSACTION)
    409     sample->set_transaction(sample_info.transaction);
    410 
    411   return true;
    412 }
    413 
    414 bool PerfSerializer::DeserializeSampleEvent(
    415     const PerfDataProto_SampleEvent& sample, event_t* event) const {
    416   perf_sample sample_info;
    417   if (sample.has_ip()) sample_info.ip = sample.ip();
    418   if (sample.has_pid()) {
    419     CHECK(sample.has_tid()) << "Cannot have PID without TID.";
    420     sample_info.pid = sample.pid();
    421     sample_info.tid = sample.tid();
    422   }
    423   if (sample.has_sample_time_ns()) sample_info.time = sample.sample_time_ns();
    424   if (sample.has_addr()) sample_info.addr = sample.addr();
    425   if (sample.has_id()) sample_info.id = sample.id();
    426   if (sample.has_stream_id()) sample_info.stream_id = sample.stream_id();
    427   if (sample.has_cpu()) sample_info.cpu = sample.cpu();
    428   if (sample.has_period()) sample_info.period = sample.period();
    429   if (sample.has_read_info()) {
    430     const SampleInfoReader* reader = GetSampleInfoReaderForEvent(*event);
    431     if (reader) {
    432       const PerfDataProto_ReadInfo& read_info = sample.read_info();
    433       if (reader->event_attr().read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
    434         sample_info.read.time_enabled = read_info.time_enabled();
    435       if (reader->event_attr().read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
    436         sample_info.read.time_running = read_info.time_running();
    437       if (reader->event_attr().read_format & PERF_FORMAT_GROUP) {
    438         sample_info.read.group.nr = read_info.read_value_size();
    439         sample_info.read.group.values =
    440             new sample_read_value[read_info.read_value_size()];
    441         for (size_t i = 0; i < sample_info.read.group.nr; i++) {
    442           sample_info.read.group.values[i].value =
    443               read_info.read_value(i).value();
    444           sample_info.read.group.values[i].id = read_info.read_value(i).id();
    445         }
    446       } else if (read_info.read_value_size() == 1) {
    447         sample_info.read.one.value = read_info.read_value(0).value();
    448         sample_info.read.one.id = read_info.read_value(0).id();
    449       } else {
    450         LOG(ERROR) << "Expected read_value array size of 1 but got "
    451                    << read_info.read_value_size();
    452       }
    453     }
    454   }
    455   if (sample.callchain_size() > 0) {
    456     uint64_t callchain_size = sample.callchain_size();
    457     sample_info.callchain = reinterpret_cast<struct ip_callchain*>(
    458         new uint64_t[callchain_size + 1]);
    459     sample_info.callchain->nr = callchain_size;
    460     for (size_t i = 0; i < callchain_size; ++i)
    461       sample_info.callchain->ips[i] = sample.callchain(i);
    462   }
    463   if (sample.raw_size() > 0) {
    464     sample_info.raw_size = sample.raw_size();
    465     sample_info.raw_data = new uint8_t[sample.raw_size()];
    466     memset(sample_info.raw_data, 0, sample.raw_size());
    467   }
    468   if (sample.branch_stack_size() > 0) {
    469     uint64_t branch_stack_size = sample.branch_stack_size();
    470     sample_info.branch_stack = reinterpret_cast<struct branch_stack*>(
    471         new uint8_t[sizeof(uint64_t) +
    472                     branch_stack_size * sizeof(struct branch_entry)]);
    473     sample_info.branch_stack->nr = branch_stack_size;
    474     for (size_t i = 0; i < branch_stack_size; ++i) {
    475       struct branch_entry& entry = sample_info.branch_stack->entries[i];
    476       memset(&entry, 0, sizeof(entry));
    477       entry.from = sample.branch_stack(i).from_ip();
    478       entry.to = sample.branch_stack(i).to_ip();
    479       entry.flags.mispred = sample.branch_stack(i).mispredicted();
    480       entry.flags.predicted = !entry.flags.mispred;
    481     }
    482   }
    483 
    484   if (sample.has_weight()) sample_info.weight = sample.weight();
    485   if (sample.has_data_src()) sample_info.data_src = sample.data_src();
    486   if (sample.has_transaction()) sample_info.transaction = sample.transaction();
    487 
    488   const SampleInfoReader* writer = GetSampleInfoReaderForId(sample.id());
    489   CHECK(writer);
    490   return writer->WritePerfSampleInfo(sample_info, event);
    491 }
    492 
    493 bool PerfSerializer::SerializeMMapEvent(const event_t& event,
    494                                         PerfDataProto_MMapEvent* sample) const {
    495   const struct mmap_event& mmap = event.mmap;
    496   sample->set_pid(mmap.pid);
    497   sample->set_tid(mmap.tid);
    498   sample->set_start(mmap.start);
    499   sample->set_len(mmap.len);
    500   sample->set_pgoff(mmap.pgoff);
    501   sample->set_filename(mmap.filename);
    502   sample->set_filename_md5_prefix(Md5Prefix(mmap.filename));
    503 
    504   return SerializeSampleInfo(event, sample->mutable_sample_info());
    505 }
    506 
    507 bool PerfSerializer::DeserializeMMapEvent(const PerfDataProto_MMapEvent& sample,
    508                                           event_t* event) const {
    509   struct mmap_event& mmap = event->mmap;
    510   mmap.pid = sample.pid();
    511   mmap.tid = sample.tid();
    512   mmap.start = sample.start();
    513   mmap.len = sample.len();
    514   mmap.pgoff = sample.pgoff();
    515   snprintf(mmap.filename, PATH_MAX, "%s", sample.filename().c_str());
    516 
    517   return DeserializeSampleInfo(sample.sample_info(), event);
    518 }
    519 
    520 bool PerfSerializer::SerializeMMap2Event(
    521     const event_t& event, PerfDataProto_MMapEvent* sample) const {
    522   const struct mmap2_event& mmap = event.mmap2;
    523   sample->set_pid(mmap.pid);
    524   sample->set_tid(mmap.tid);
    525   sample->set_start(mmap.start);
    526   sample->set_len(mmap.len);
    527   sample->set_pgoff(mmap.pgoff);
    528   sample->set_maj(mmap.maj);
    529   sample->set_min(mmap.min);
    530   sample->set_ino(mmap.ino);
    531   sample->set_ino_generation(mmap.ino_generation);
    532   sample->set_prot(mmap.prot);
    533   sample->set_flags(mmap.flags);
    534   sample->set_filename(mmap.filename);
    535   sample->set_filename_md5_prefix(Md5Prefix(mmap.filename));
    536 
    537   return SerializeSampleInfo(event, sample->mutable_sample_info());
    538 }
    539 
    540 bool PerfSerializer::DeserializeMMap2Event(
    541     const PerfDataProto_MMapEvent& sample, event_t* event) const {
    542   struct mmap2_event& mmap = event->mmap2;
    543   mmap.pid = sample.pid();
    544   mmap.tid = sample.tid();
    545   mmap.start = sample.start();
    546   mmap.len = sample.len();
    547   mmap.pgoff = sample.pgoff();
    548   mmap.maj = sample.maj();
    549   mmap.min = sample.min();
    550   mmap.ino = sample.ino();
    551   mmap.ino_generation = sample.ino_generation();
    552   mmap.prot = sample.prot();
    553   mmap.flags = sample.flags();
    554   snprintf(mmap.filename, PATH_MAX, "%s", sample.filename().c_str());
    555 
    556   return DeserializeSampleInfo(sample.sample_info(), event);
    557 }
    558 
    559 bool PerfSerializer::SerializeCommEvent(const event_t& event,
    560                                         PerfDataProto_CommEvent* sample) const {
    561   const struct comm_event& comm = event.comm;
    562   sample->set_pid(comm.pid);
    563   sample->set_tid(comm.tid);
    564   sample->set_comm(comm.comm);
    565   sample->set_comm_md5_prefix(Md5Prefix(comm.comm));
    566 
    567   return SerializeSampleInfo(event, sample->mutable_sample_info());
    568 }
    569 
    570 bool PerfSerializer::DeserializeCommEvent(const PerfDataProto_CommEvent& sample,
    571                                           event_t* event) const {
    572   struct comm_event& comm = event->comm;
    573   comm.pid = sample.pid();
    574   comm.tid = sample.tid();
    575   snprintf(comm.comm, sizeof(comm.comm), "%s", sample.comm().c_str());
    576 
    577   // Sometimes the command string will be modified.  e.g. if the original comm
    578   // string is not recoverable from the Md5sum prefix, then use the latter as a
    579   // replacement comm string.  However, if the original was < 8 bytes (fit into
    580   // |sizeof(uint64_t)|), then the size is no longer correct.  This section
    581   // checks for the size difference and updates the size in the header.
    582   const SampleInfoReader* reader =
    583       GetSampleInfoReaderForId(sample.sample_info().id());
    584   CHECK(reader);
    585   uint64_t sample_fields = SampleInfoReader::GetSampleFieldsForEventType(
    586       comm.header.type, reader->event_attr().sample_type);
    587   comm.header.size = SampleInfoReader::GetPerfSampleDataOffset(*event) +
    588                      GetNumBits(sample_fields) * sizeof(uint64_t);
    589 
    590   return DeserializeSampleInfo(sample.sample_info(), event);
    591 }
    592 
    593 bool PerfSerializer::SerializeForkExitEvent(
    594     const event_t& event, PerfDataProto_ForkEvent* sample) const {
    595   const struct fork_event& fork = event.fork;
    596   sample->set_pid(fork.pid);
    597   sample->set_ppid(fork.ppid);
    598   sample->set_tid(fork.tid);
    599   sample->set_ptid(fork.ptid);
    600   sample->set_fork_time_ns(fork.time);
    601 
    602   return SerializeSampleInfo(event, sample->mutable_sample_info());
    603 }
    604 
    605 bool PerfSerializer::DeserializeForkExitEvent(
    606     const PerfDataProto_ForkEvent& sample, event_t* event) const {
    607   struct fork_event& fork = event->fork;
    608   fork.pid = sample.pid();
    609   fork.ppid = sample.ppid();
    610   fork.tid = sample.tid();
    611   fork.ptid = sample.ptid();
    612   fork.time = sample.fork_time_ns();
    613 
    614   return DeserializeSampleInfo(sample.sample_info(), event);
    615 }
    616 
    617 bool PerfSerializer::SerializeLostEvent(const event_t& event,
    618                                         PerfDataProto_LostEvent* sample) const {
    619   const struct lost_event& lost = event.lost;
    620   sample->set_id(lost.id);
    621   sample->set_lost(lost.lost);
    622 
    623   return SerializeSampleInfo(event, sample->mutable_sample_info());
    624 }
    625 
    626 bool PerfSerializer::DeserializeLostEvent(const PerfDataProto_LostEvent& sample,
    627                                           event_t* event) const {
    628   struct lost_event& lost = event->lost;
    629   lost.id = sample.id();
    630   lost.lost = sample.lost();
    631 
    632   return DeserializeSampleInfo(sample.sample_info(), event);
    633 }
    634 
    635 bool PerfSerializer::SerializeThrottleEvent(
    636     const event_t& event, PerfDataProto_ThrottleEvent* sample) const {
    637   const struct throttle_event& throttle = event.throttle;
    638   sample->set_time_ns(throttle.time);
    639   sample->set_id(throttle.id);
    640   sample->set_stream_id(throttle.stream_id);
    641 
    642   return SerializeSampleInfo(event, sample->mutable_sample_info());
    643 }
    644 
    645 bool PerfSerializer::DeserializeThrottleEvent(
    646     const PerfDataProto_ThrottleEvent& sample, event_t* event) const {
    647   struct throttle_event& throttle = event->throttle;
    648   throttle.time = sample.time_ns();
    649   throttle.id = sample.id();
    650   throttle.stream_id = sample.stream_id();
    651 
    652   return DeserializeSampleInfo(sample.sample_info(), event);
    653 }
    654 
    655 bool PerfSerializer::SerializeReadEvent(const event_t& event,
    656                                         PerfDataProto_ReadEvent* sample) const {
    657   const struct read_event& read = event.read;
    658   sample->set_pid(read.pid);
    659   sample->set_tid(read.tid);
    660   sample->set_value(read.value);
    661   sample->set_time_enabled(read.time_enabled);
    662   sample->set_time_running(read.time_running);
    663   sample->set_id(read.id);
    664 
    665   return true;
    666 }
    667 
    668 bool PerfSerializer::DeserializeReadEvent(const PerfDataProto_ReadEvent& sample,
    669                                           event_t* event) const {
    670   struct read_event& read = event->read;
    671   read.pid = sample.pid();
    672   read.tid = sample.tid();
    673   read.value = sample.value();
    674   read.time_enabled = sample.time_enabled();
    675   read.time_running = sample.time_running();
    676   read.id = sample.id();
    677 
    678   return true;
    679 }
    680 
    681 bool PerfSerializer::SerializeAuxEvent(const event_t& event,
    682                                        PerfDataProto_AuxEvent* sample) const {
    683   const struct aux_event& aux = event.aux;
    684   sample->set_aux_offset(aux.aux_offset);
    685   sample->set_aux_size(aux.aux_size);
    686   sample->set_is_truncated(aux.flags & PERF_AUX_FLAG_TRUNCATED ? true : false);
    687   sample->set_is_overwrite(aux.flags & PERF_AUX_FLAG_OVERWRITE ? true : false);
    688   sample->set_is_partial(aux.flags & PERF_AUX_FLAG_PARTIAL ? true : false);
    689   if (aux.flags & ~(PERF_AUX_FLAG_TRUNCATED | PERF_AUX_FLAG_OVERWRITE |
    690                     PERF_AUX_FLAG_PARTIAL)) {
    691     LOG(WARNING) << "Ignoring unknown PERF_RECORD_AUX flag: " << aux.flags;
    692   }
    693 
    694   return SerializeSampleInfo(event, sample->mutable_sample_info());
    695 }
    696 
    697 bool PerfSerializer::DeserializeAuxEvent(const PerfDataProto_AuxEvent& sample,
    698                                          event_t* event) const {
    699   struct aux_event& aux = event->aux;
    700   aux.aux_offset = sample.aux_offset();
    701   aux.aux_size = sample.aux_size();
    702   aux.flags |= sample.is_truncated() ? PERF_AUX_FLAG_TRUNCATED : 0;
    703   aux.flags |= sample.is_overwrite() ? PERF_AUX_FLAG_OVERWRITE : 0;
    704   aux.flags |= sample.is_partial() ? PERF_AUX_FLAG_PARTIAL : 0;
    705 
    706   return DeserializeSampleInfo(sample.sample_info(), event);
    707 }
    708 
    709 bool PerfSerializer::SerializeSampleInfo(
    710     const event_t& event, PerfDataProto_SampleInfo* sample) const {
    711   if (!SampleIdAll()) return true;
    712 
    713   perf_sample sample_info;
    714   uint64_t sample_type = 0;
    715   if (!ReadPerfSampleInfoAndType(event, &sample_info, &sample_type))
    716     return false;
    717 
    718   if (sample_type & PERF_SAMPLE_TID) {
    719     sample->set_pid(sample_info.pid);
    720     sample->set_tid(sample_info.tid);
    721   }
    722   if (sample_type & PERF_SAMPLE_TIME)
    723     sample->set_sample_time_ns(sample_info.time);
    724   if ((sample_type & PERF_SAMPLE_ID) || (sample_type & PERF_SAMPLE_IDENTIFIER))
    725     sample->set_id(sample_info.id);
    726   if (sample_type & PERF_SAMPLE_CPU) sample->set_cpu(sample_info.cpu);
    727   if (sample_type & PERF_SAMPLE_STREAM_ID)
    728     sample->set_stream_id(sample_info.stream_id);
    729   return true;
    730 }
    731 
    732 bool PerfSerializer::DeserializeSampleInfo(
    733     const PerfDataProto_SampleInfo& sample, event_t* event) const {
    734   if (!SampleIdAll()) return true;
    735 
    736   perf_sample sample_info;
    737   if (sample.has_tid()) {
    738     sample_info.pid = sample.pid();
    739     sample_info.tid = sample.tid();
    740   }
    741   if (sample.has_sample_time_ns()) sample_info.time = sample.sample_time_ns();
    742   if (sample.has_id()) sample_info.id = sample.id();
    743   if (sample.has_cpu()) sample_info.cpu = sample.cpu();
    744   if (sample.has_stream_id()) sample_info.stream_id = sample.stream_id();
    745 
    746   const SampleInfoReader* writer = GetSampleInfoReaderForId(sample.id());
    747   CHECK(writer);
    748   return writer->WritePerfSampleInfo(sample_info, event);
    749 }
    750 
    751 bool PerfSerializer::SerializeTracingMetadata(const std::vector<char>& from,
    752                                               PerfDataProto* to) const {
    753   if (from.empty()) {
    754     return true;
    755   }
    756   PerfDataProto_PerfTracingMetadata* data = to->mutable_tracing_data();
    757   data->set_tracing_data(from.data(), from.size());
    758   data->set_tracing_data_md5_prefix(Md5Prefix(from));
    759 
    760   return true;
    761 }
    762 
    763 bool PerfSerializer::DeserializeTracingMetadata(const PerfDataProto& from,
    764                                                 std::vector<char>* to) const {
    765   if (!from.has_tracing_data()) {
    766     to->clear();
    767     return true;
    768   }
    769 
    770   const PerfDataProto_PerfTracingMetadata& data = from.tracing_data();
    771   to->assign(data.tracing_data().begin(), data.tracing_data().end());
    772   return true;
    773 }
    774 
    775 bool PerfSerializer::SerializeBuildIDEvent(
    776     const malloced_unique_ptr<build_id_event>& from,
    777     PerfDataProto_PerfBuildID* to) const {
    778   to->set_misc(from->header.misc);
    779   to->set_pid(from->pid);
    780   to->set_filename(from->filename);
    781   to->set_filename_md5_prefix(Md5Prefix(from->filename));
    782 
    783   // Trim out trailing zeroes from the build ID.
    784   string build_id = RawDataToHexString(from->build_id, kBuildIDArraySize);
    785   TrimZeroesFromBuildIDString(&build_id);
    786 
    787   uint8_t build_id_bytes[kBuildIDArraySize];
    788   if (!HexStringToRawData(build_id, build_id_bytes, sizeof(build_id_bytes)))
    789     return false;
    790 
    791   // Used to convert build IDs (and possibly other hashes) between raw data
    792   // format and as string of hex digits.
    793   const int kHexCharsPerByte = 2;
    794   to->set_build_id_hash(build_id_bytes, build_id.size() / kHexCharsPerByte);
    795 
    796   return true;
    797 }
    798 
    799 bool PerfSerializer::DeserializeBuildIDEvent(
    800     const PerfDataProto_PerfBuildID& from,
    801     malloced_unique_ptr<build_id_event>* to) const {
    802   const string& filename = from.filename();
    803   size_t size = sizeof(build_id_event) + GetUint64AlignedStringLength(filename);
    804 
    805   malloced_unique_ptr<build_id_event>& event = *to;
    806   event.reset(CallocMemoryForBuildID(size));
    807   event->header.type = PERF_RECORD_HEADER_BUILD_ID;
    808   event->header.size = size;
    809   event->header.misc = from.misc();
    810   event->pid = from.pid();
    811   memcpy(event->build_id, from.build_id_hash().c_str(),
    812          from.build_id_hash().size());
    813 
    814   if (from.has_filename() && !filename.empty()) {
    815     CHECK_GT(
    816         snprintf(event->filename, filename.size() + 1, "%s", filename.c_str()),
    817         0);
    818   }
    819   return true;
    820 }
    821 
    822 bool PerfSerializer::SerializeAuxtraceEvent(
    823     const event_t& event, PerfDataProto_AuxtraceEvent* sample) const {
    824   const struct auxtrace_event& auxtrace = event.auxtrace;
    825   sample->set_size(auxtrace.size);
    826   sample->set_offset(auxtrace.offset);
    827   sample->set_reference(auxtrace.reference);
    828   sample->set_idx(auxtrace.idx);
    829   sample->set_tid(auxtrace.tid);
    830   sample->set_cpu(auxtrace.cpu);
    831 
    832   return true;
    833 }
    834 
    835 bool PerfSerializer::SerializeAuxtraceEventTraceData(
    836     const std::vector<char>& from, PerfDataProto_AuxtraceEvent* to) const {
    837   if (from.empty()) {
    838     return true;
    839   }
    840   to->set_trace_data(from.data(), from.size());
    841 
    842   return true;
    843 }
    844 
    845 bool PerfSerializer::DeserializeAuxtraceEvent(
    846     const PerfDataProto_AuxtraceEvent& sample, event_t* event) const {
    847   struct auxtrace_event& auxtrace = event->auxtrace;
    848   auxtrace.size = sample.size();
    849   auxtrace.offset = sample.offset();
    850   auxtrace.reference = sample.reference();
    851   auxtrace.idx = sample.idx();
    852   auxtrace.tid = sample.tid();
    853   auxtrace.cpu = sample.cpu();
    854 
    855   return true;
    856 }
    857 
    858 bool PerfSerializer::DeserializeAuxtraceEventTraceData(
    859     const PerfDataProto_AuxtraceEvent& from, std::vector<char>* to) const {
    860   to->assign(from.trace_data().begin(), from.trace_data().end());
    861   return true;
    862 }
    863 
    864 bool PerfSerializer::SerializeSingleUint32Metadata(
    865     const PerfUint32Metadata& metadata,
    866     PerfDataProto_PerfUint32Metadata* proto_metadata) const {
    867   proto_metadata->set_type(metadata.type);
    868   for (size_t i = 0; i < metadata.data.size(); ++i)
    869     proto_metadata->add_data(metadata.data[i]);
    870   return true;
    871 }
    872 
    873 bool PerfSerializer::DeserializeSingleUint32Metadata(
    874     const PerfDataProto_PerfUint32Metadata& proto_metadata,
    875     PerfUint32Metadata* metadata) const {
    876   metadata->type = proto_metadata.type();
    877   for (int i = 0; i < proto_metadata.data_size(); ++i)
    878     metadata->data.push_back(proto_metadata.data(i));
    879   return true;
    880 }
    881 
    882 bool PerfSerializer::SerializeSingleUint64Metadata(
    883     const PerfUint64Metadata& metadata,
    884     PerfDataProto_PerfUint64Metadata* proto_metadata) const {
    885   proto_metadata->set_type(metadata.type);
    886   for (size_t i = 0; i < metadata.data.size(); ++i)
    887     proto_metadata->add_data(metadata.data[i]);
    888   return true;
    889 }
    890 
    891 bool PerfSerializer::DeserializeSingleUint64Metadata(
    892     const PerfDataProto_PerfUint64Metadata& proto_metadata,
    893     PerfUint64Metadata* metadata) const {
    894   metadata->type = proto_metadata.type();
    895   for (int i = 0; i < proto_metadata.data_size(); ++i)
    896     metadata->data.push_back(proto_metadata.data(i));
    897   return true;
    898 }
    899 
    900 bool PerfSerializer::SerializeCPUTopologyMetadata(
    901     const PerfCPUTopologyMetadata& metadata,
    902     PerfDataProto_PerfCPUTopologyMetadata* proto_metadata) const {
    903   for (const string& core_name : metadata.core_siblings) {
    904     proto_metadata->add_core_siblings(core_name);
    905     proto_metadata->add_core_siblings_md5_prefix(Md5Prefix(core_name));
    906   }
    907   for (const string& thread_name : metadata.thread_siblings) {
    908     proto_metadata->add_thread_siblings(thread_name);
    909     proto_metadata->add_thread_siblings_md5_prefix(Md5Prefix(thread_name));
    910   }
    911   return true;
    912 }
    913 
    914 bool PerfSerializer::DeserializeCPUTopologyMetadata(
    915     const PerfDataProto_PerfCPUTopologyMetadata& proto_metadata,
    916     PerfCPUTopologyMetadata* metadata) const {
    917   metadata->core_siblings.clear();
    918   metadata->core_siblings.reserve(proto_metadata.core_siblings().size());
    919   std::copy(proto_metadata.core_siblings().begin(),
    920             proto_metadata.core_siblings().end(),
    921             std::back_inserter(metadata->core_siblings));
    922 
    923   metadata->thread_siblings.clear();
    924   metadata->thread_siblings.reserve(proto_metadata.thread_siblings().size());
    925   std::copy(proto_metadata.thread_siblings().begin(),
    926             proto_metadata.thread_siblings().end(),
    927             std::back_inserter(metadata->thread_siblings));
    928   return true;
    929 }
    930 
    931 bool PerfSerializer::SerializeNodeTopologyMetadata(
    932     const PerfNodeTopologyMetadata& metadata,
    933     PerfDataProto_PerfNodeTopologyMetadata* proto_metadata) const {
    934   proto_metadata->set_id(metadata.id);
    935   proto_metadata->set_total_memory(metadata.total_memory);
    936   proto_metadata->set_free_memory(metadata.free_memory);
    937   proto_metadata->set_cpu_list(metadata.cpu_list);
    938   proto_metadata->set_cpu_list_md5_prefix(Md5Prefix(metadata.cpu_list));
    939   return true;
    940 }
    941 
    942 bool PerfSerializer::DeserializeNodeTopologyMetadata(
    943     const PerfDataProto_PerfNodeTopologyMetadata& proto_metadata,
    944     PerfNodeTopologyMetadata* metadata) const {
    945   metadata->id = proto_metadata.id();
    946   metadata->total_memory = proto_metadata.total_memory();
    947   metadata->free_memory = proto_metadata.free_memory();
    948   metadata->cpu_list = proto_metadata.cpu_list();
    949   return true;
    950 }
    951 
    952 bool PerfSerializer::SerializePMUMappingsMetadata(
    953     const PerfPMUMappingsMetadata& metadata,
    954     PerfDataProto_PerfPMUMappingsMetadata* proto_metadata) const {
    955   proto_metadata->set_type(metadata.type);
    956   proto_metadata->set_name(metadata.name);
    957   proto_metadata->set_name_md5_prefix(Md5Prefix(metadata.name));
    958   return true;
    959 }
    960 
    961 bool PerfSerializer::DeserializePMUMappingsMetadata(
    962     const PerfDataProto_PerfPMUMappingsMetadata& proto_metadata,
    963     PerfPMUMappingsMetadata* metadata) const {
    964   metadata->type = proto_metadata.type();
    965   metadata->name = proto_metadata.name();
    966   return true;
    967 }
    968 
    969 bool PerfSerializer::SerializeGroupDescMetadata(
    970     const PerfGroupDescMetadata& metadata,
    971     PerfDataProto_PerfGroupDescMetadata* proto_metadata) const {
    972   proto_metadata->set_name(metadata.name);
    973   proto_metadata->set_name_md5_prefix(Md5Prefix(metadata.name));
    974   proto_metadata->set_leader_idx(metadata.leader_idx);
    975   proto_metadata->set_num_members(metadata.num_members);
    976   return true;
    977 }
    978 
    979 bool PerfSerializer::DeserializeGroupDescMetadata(
    980     const PerfDataProto_PerfGroupDescMetadata& proto_metadata,
    981     PerfGroupDescMetadata* metadata) const {
    982   metadata->name = proto_metadata.name();
    983   metadata->leader_idx = proto_metadata.leader_idx();
    984   metadata->num_members = proto_metadata.num_members();
    985   return true;
    986 }
    987 
    988 // static
    989 void PerfSerializer::SerializeParserStats(const PerfEventStats& stats,
    990                                           PerfDataProto* perf_data_proto) {
    991   PerfDataProto_PerfEventStats* stats_pb = perf_data_proto->mutable_stats();
    992   stats_pb->set_num_sample_events(stats.num_sample_events);
    993   stats_pb->set_num_mmap_events(stats.num_mmap_events);
    994   stats_pb->set_num_fork_events(stats.num_fork_events);
    995   stats_pb->set_num_exit_events(stats.num_exit_events);
    996   stats_pb->set_did_remap(stats.did_remap);
    997   stats_pb->set_num_sample_events_mapped(stats.num_sample_events_mapped);
    998 }
    999 
   1000 // static
   1001 void PerfSerializer::DeserializeParserStats(
   1002     const PerfDataProto& perf_data_proto, PerfEventStats* stats) {
   1003   const PerfDataProto_PerfEventStats& stats_pb = perf_data_proto.stats();
   1004   stats->num_sample_events = stats_pb.num_sample_events();
   1005   stats->num_mmap_events = stats_pb.num_mmap_events();
   1006   stats->num_fork_events = stats_pb.num_fork_events();
   1007   stats->num_exit_events = stats_pb.num_exit_events();
   1008   stats->did_remap = stats_pb.did_remap();
   1009   stats->num_sample_events_mapped = stats_pb.num_sample_events_mapped();
   1010 }
   1011 
   1012 void PerfSerializer::CreateSampleInfoReader(const PerfFileAttr& attr,
   1013                                             bool read_cross_endian) {
   1014   for (const auto& id :
   1015        (attr.ids.empty() ? std::initializer_list<u64>({0}) : attr.ids)) {
   1016     sample_info_reader_map_[id].reset(
   1017         new SampleInfoReader(attr.attr, read_cross_endian));
   1018   }
   1019   UpdateEventIdPositions(attr.attr);
   1020 }
   1021 
   1022 void PerfSerializer::UpdateEventIdPositions(
   1023     const struct perf_event_attr& attr) {
   1024   const u64 sample_type = attr.sample_type;
   1025   ssize_t new_sample_event_id_pos = EventIdPosition::NotPresent;
   1026   ssize_t new_other_event_id_pos = EventIdPosition::NotPresent;
   1027   if (sample_type & PERF_SAMPLE_IDENTIFIER) {
   1028     new_sample_event_id_pos = 0;
   1029     new_other_event_id_pos = 1;
   1030   } else if (sample_type & PERF_SAMPLE_ID) {
   1031     // Increment for IP, TID, TIME, ADDR
   1032     new_sample_event_id_pos = 0;
   1033     if (sample_type & PERF_SAMPLE_IP) new_sample_event_id_pos++;
   1034     if (sample_type & PERF_SAMPLE_TID) new_sample_event_id_pos++;
   1035     if (sample_type & PERF_SAMPLE_TIME) new_sample_event_id_pos++;
   1036     if (sample_type & PERF_SAMPLE_ADDR) new_sample_event_id_pos++;
   1037 
   1038     // Increment for CPU, STREAM_ID
   1039     new_other_event_id_pos = 1;
   1040     if (sample_type & PERF_SAMPLE_CPU) new_other_event_id_pos++;
   1041     if (sample_type & PERF_SAMPLE_STREAM_ID) new_other_event_id_pos++;
   1042   }
   1043 
   1044   if (sample_event_id_pos_ == EventIdPosition::Uninitialized) {
   1045     sample_event_id_pos_ = new_sample_event_id_pos;
   1046   } else {
   1047     CHECK_EQ(new_sample_event_id_pos, sample_event_id_pos_)
   1048         << "Event ids must be in a consistent positition";
   1049   }
   1050   if (other_event_id_pos_ == EventIdPosition::Uninitialized) {
   1051     other_event_id_pos_ = new_other_event_id_pos;
   1052   } else {
   1053     CHECK_EQ(new_other_event_id_pos, other_event_id_pos_)
   1054         << "Event ids must be in a consistent positition";
   1055   }
   1056 }
   1057 
   1058 bool PerfSerializer::SampleIdAll() const {
   1059   if (sample_info_reader_map_.empty()) {
   1060     return false;
   1061   }
   1062   return sample_info_reader_map_.begin()->second->event_attr().sample_id_all;
   1063 }
   1064 
   1065 const SampleInfoReader* PerfSerializer::GetSampleInfoReaderForEvent(
   1066     const event_t& event) const {
   1067   // Where is the event id?
   1068   ssize_t event_id_pos = EventIdPosition::Uninitialized;
   1069   if (event.header.type == PERF_RECORD_SAMPLE) {
   1070     event_id_pos = sample_event_id_pos_;
   1071   } else if (SampleIdAll()) {
   1072     event_id_pos = other_event_id_pos_;
   1073   } else {
   1074     event_id_pos = EventIdPosition::NotPresent;
   1075   }
   1076 
   1077   // What is the event id?
   1078   u64 event_id;
   1079   switch (event_id_pos) {
   1080     case EventIdPosition::Uninitialized:
   1081       LOG(FATAL) << "Position of the event id was not initialized!";
   1082       return nullptr;
   1083     case EventIdPosition::NotPresent:
   1084       event_id = 0;
   1085       break;
   1086     default:
   1087       if (event.header.type == PERF_RECORD_SAMPLE) {
   1088         event_id = event.sample.array[event_id_pos];
   1089       } else {
   1090         // Pretend this is a sample event--ie, an array of u64. Find the length
   1091         // of the array. The sample id is at the end of the array, and
   1092         // event_id_pos (aka other_event_id_pos_) counts from the end.
   1093         size_t event_end_pos =
   1094             (event.header.size - sizeof(event.header)) / sizeof(u64);
   1095         event_id = event.sample.array[event_end_pos - event_id_pos];
   1096       }
   1097       break;
   1098   }
   1099   return GetSampleInfoReaderForId(event_id);
   1100 }
   1101 
   1102 const SampleInfoReader* PerfSerializer::GetSampleInfoReaderForId(
   1103     uint64_t id) const {
   1104   if (id) {
   1105     auto iter = sample_info_reader_map_.find(id);
   1106     if (iter == sample_info_reader_map_.end()) return nullptr;
   1107     return iter->second.get();
   1108   }
   1109 
   1110   if (sample_info_reader_map_.empty()) return nullptr;
   1111   return sample_info_reader_map_.begin()->second.get();
   1112 }
   1113 
   1114 bool PerfSerializer::ReadPerfSampleInfoAndType(const event_t& event,
   1115                                                perf_sample* sample_info,
   1116                                                uint64_t* sample_type) const {
   1117   const SampleInfoReader* reader = GetSampleInfoReaderForEvent(event);
   1118   if (!reader) {
   1119     LOG(ERROR) << "No SampleInfoReader available";
   1120     return false;
   1121   }
   1122 
   1123   if (!reader->ReadPerfSampleInfo(event, sample_info)) return false;
   1124   *sample_type = reader->event_attr().sample_type;
   1125   return true;
   1126 }
   1127 
   1128 }  // namespace quipper
   1129