Home | History | Annotate | Download | only in quipper
      1 // Copyright 2015 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 "sample_info_reader.h"
      6 
      7 #include <string.h>
      8 
      9 #include "base/logging.h"
     10 #include "buffer_reader.h"
     11 #include "buffer_writer.h"
     12 #include "kernel/perf_internals.h"
     13 #include "perf_data_utils.h"
     14 
     15 namespace quipper {
     16 
     17 namespace {
     18 
     19 bool IsSupportedEventType(uint32_t type) {
     20   switch (type) {
     21     case PERF_RECORD_SAMPLE:
     22     case PERF_RECORD_MMAP:
     23     case PERF_RECORD_MMAP2:
     24     case PERF_RECORD_FORK:
     25     case PERF_RECORD_EXIT:
     26     case PERF_RECORD_COMM:
     27     case PERF_RECORD_LOST:
     28     case PERF_RECORD_THROTTLE:
     29     case PERF_RECORD_UNTHROTTLE:
     30     case PERF_RECORD_AUX:
     31       return true;
     32     case PERF_RECORD_READ:
     33     case PERF_RECORD_MAX:
     34       return false;
     35     default:
     36       LOG(FATAL) << "Unknown event type " << type;
     37       return false;
     38   }
     39 }
     40 
     41 // Read read info from perf data.  Corresponds to sample format type
     42 // PERF_SAMPLE_READ in the !PERF_FORMAT_GROUP case.
     43 void ReadReadInfo(DataReader* reader, uint64_t read_format,
     44                   struct perf_sample* sample) {
     45   reader->ReadUint64(&sample->read.one.value);
     46   if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
     47     reader->ReadUint64(&sample->read.time_enabled);
     48   if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
     49     reader->ReadUint64(&sample->read.time_running);
     50   if (read_format & PERF_FORMAT_ID) reader->ReadUint64(&sample->read.one.id);
     51 }
     52 
     53 // Read read info from perf data.  Corresponds to sample format type
     54 // PERF_SAMPLE_READ in the PERF_FORMAT_GROUP case.
     55 void ReadGroupReadInfo(DataReader* reader, uint64_t read_format,
     56                        struct perf_sample* sample) {
     57   uint64_t num = 0;
     58   reader->ReadUint64(&num);
     59   if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
     60     reader->ReadUint64(&sample->read.time_enabled);
     61   if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
     62     reader->ReadUint64(&sample->read.time_running);
     63 
     64   // Make sure there is no existing allocated memory in
     65   // |sample->read.group.values|.
     66   CHECK_EQ(static_cast<void*>(NULL), sample->read.group.values);
     67   sample_read_value* values = new sample_read_value[num];
     68   for (uint64_t i = 0; i < num; i++) {
     69     reader->ReadUint64(&values[i].value);
     70     if (read_format & PERF_FORMAT_ID) reader->ReadUint64(&values[i].id);
     71   }
     72   sample->read.group.nr = num;
     73   sample->read.group.values = values;
     74 }
     75 
     76 // Read call chain info from perf data.  Corresponds to sample format type
     77 // PERF_SAMPLE_CALLCHAIN.
     78 void ReadCallchain(DataReader* reader, struct perf_sample* sample) {
     79   // Make sure there is no existing allocated memory in |sample->callchain|.
     80   CHECK_EQ(static_cast<void*>(NULL), sample->callchain);
     81 
     82   // The callgraph data consists of a uint64_t value |nr| followed by |nr|
     83   // addresses.
     84   uint64_t callchain_size = 0;
     85   reader->ReadUint64(&callchain_size);
     86 
     87   struct ip_callchain* callchain =
     88       reinterpret_cast<struct ip_callchain*>(new uint64_t[callchain_size + 1]);
     89   callchain->nr = callchain_size;
     90 
     91   for (size_t i = 0; i < callchain_size; ++i)
     92     reader->ReadUint64(&callchain->ips[i]);
     93 
     94   sample->callchain = callchain;
     95 }
     96 
     97 // Read raw info from perf data.  Corresponds to sample format type
     98 // PERF_SAMPLE_RAW.
     99 void ReadRawData(DataReader* reader, struct perf_sample* sample) {
    100   // Save the original read offset.
    101   size_t reader_offset = reader->Tell();
    102 
    103   reader->ReadUint32(&sample->raw_size);
    104 
    105   // Allocate space for and read the raw data bytes.
    106   sample->raw_data = new uint8_t[sample->raw_size];
    107   reader->ReadData(sample->raw_size, sample->raw_data);
    108 
    109   // Determine the bytes that were read, and align to the next 64 bits.
    110   reader_offset += Align<uint64_t>(sizeof(sample->raw_size) + sample->raw_size);
    111   reader->SeekSet(reader_offset);
    112 }
    113 
    114 // Read call chain info from perf data.  Corresponds to sample format type
    115 // PERF_SAMPLE_CALLCHAIN.
    116 void ReadBranchStack(DataReader* reader, struct perf_sample* sample) {
    117   // Make sure there is no existing allocated memory in
    118   // |sample->branch_stack|.
    119   CHECK_EQ(static_cast<void*>(NULL), sample->branch_stack);
    120 
    121   // The branch stack data consists of a uint64_t value |nr| followed by |nr|
    122   // branch_entry structs.
    123   uint64_t branch_stack_size = 0;
    124   reader->ReadUint64(&branch_stack_size);
    125 
    126   struct branch_stack* branch_stack = reinterpret_cast<struct branch_stack*>(
    127       new uint8_t[sizeof(uint64_t) +
    128                   branch_stack_size * sizeof(struct branch_entry)]);
    129   branch_stack->nr = branch_stack_size;
    130   for (size_t i = 0; i < branch_stack_size; ++i) {
    131     reader->ReadUint64(&branch_stack->entries[i].from);
    132     reader->ReadUint64(&branch_stack->entries[i].to);
    133     reader->ReadData(sizeof(branch_stack->entries[i].flags),
    134                      &branch_stack->entries[i].flags);
    135     if (reader->is_cross_endian()) {
    136       LOG(ERROR) << "Byte swapping of branch stack flags is not yet supported.";
    137     }
    138   }
    139   sample->branch_stack = branch_stack;
    140 }
    141 
    142 // Reads perf sample info data from |event| into |sample|.
    143 // |attr| is the event attribute struct, which contains info such as which
    144 // sample info fields are present.
    145 // |is_cross_endian| indicates that the data is cross-endian and that the byte
    146 // order should be reversed for each field according to its size.
    147 // Returns number of bytes of data read or skipped.
    148 size_t ReadPerfSampleFromData(const event_t& event,
    149                               const struct perf_event_attr& attr,
    150                               bool is_cross_endian,
    151                               struct perf_sample* sample) {
    152   BufferReader reader(&event, event.header.size);
    153   reader.set_is_cross_endian(is_cross_endian);
    154   reader.SeekSet(SampleInfoReader::GetPerfSampleDataOffset(event));
    155 
    156   if (!(event.header.type == PERF_RECORD_SAMPLE || attr.sample_id_all)) {
    157     return reader.Tell();
    158   }
    159 
    160   uint64_t sample_fields = SampleInfoReader::GetSampleFieldsForEventType(
    161       event.header.type, attr.sample_type);
    162 
    163   // See structure for PERF_RECORD_SAMPLE in kernel/perf_event.h
    164   // and compare sample_id when sample_id_all is set.
    165 
    166   // NB: For sample_id, sample_fields has already been masked to the set
    167   // of fields in that struct by GetSampleFieldsForEventType. That set
    168   // of fields is mostly in the same order as PERF_RECORD_SAMPLE, with
    169   // the exception of PERF_SAMPLE_IDENTIFIER.
    170 
    171   // PERF_SAMPLE_IDENTIFIER is in a different location depending on
    172   // if this is a SAMPLE event or the sample_id of another event.
    173   if (event.header.type == PERF_RECORD_SAMPLE) {
    174     // { u64                   id;       } && PERF_SAMPLE_IDENTIFIER
    175     if (sample_fields & PERF_SAMPLE_IDENTIFIER) {
    176       reader.ReadUint64(&sample->id);
    177     }
    178   }
    179 
    180   // { u64                   ip;       } && PERF_SAMPLE_IP
    181   if (sample_fields & PERF_SAMPLE_IP) {
    182     reader.ReadUint64(&sample->ip);
    183   }
    184 
    185   // { u32                   pid, tid; } && PERF_SAMPLE_TID
    186   if (sample_fields & PERF_SAMPLE_TID) {
    187     reader.ReadUint32(&sample->pid);
    188     reader.ReadUint32(&sample->tid);
    189   }
    190 
    191   // { u64                   time;     } && PERF_SAMPLE_TIME
    192   if (sample_fields & PERF_SAMPLE_TIME) {
    193     reader.ReadUint64(&sample->time);
    194   }
    195 
    196   // { u64                   addr;     } && PERF_SAMPLE_ADDR
    197   if (sample_fields & PERF_SAMPLE_ADDR) {
    198     reader.ReadUint64(&sample->addr);
    199   }
    200 
    201   // { u64                   id;       } && PERF_SAMPLE_ID
    202   if (sample_fields & PERF_SAMPLE_ID) {
    203     reader.ReadUint64(&sample->id);
    204   }
    205 
    206   // { u64                   stream_id;} && PERF_SAMPLE_STREAM_ID
    207   if (sample_fields & PERF_SAMPLE_STREAM_ID) {
    208     reader.ReadUint64(&sample->stream_id);
    209   }
    210 
    211   // { u32                   cpu, res; } && PERF_SAMPLE_CPU
    212   if (sample_fields & PERF_SAMPLE_CPU) {
    213     reader.ReadUint32(&sample->cpu);
    214 
    215     // The PERF_SAMPLE_CPU format bit specifies 64-bits of data, but the actual
    216     // CPU number is really only 32 bits. There is an extra 32-bit word of
    217     // reserved padding, as the whole field is aligned to 64 bits.
    218 
    219     // reader.ReadUint32(&sample->res);  // reserved
    220     u32 reserved;
    221     reader.ReadUint32(&reserved);
    222   }
    223 
    224   // This is the location of PERF_SAMPLE_IDENTIFIER in struct sample_id.
    225   if (event.header.type != PERF_RECORD_SAMPLE) {
    226     // { u64                   id;       } && PERF_SAMPLE_IDENTIFIER
    227     if (sample_fields & PERF_SAMPLE_IDENTIFIER) {
    228       reader.ReadUint64(&sample->id);
    229     }
    230   }
    231 
    232   //
    233   // The remaining fields are only in PERF_RECORD_SAMPLE
    234   //
    235 
    236   // { u64                   period;   } && PERF_SAMPLE_PERIOD
    237   if (sample_fields & PERF_SAMPLE_PERIOD) {
    238     reader.ReadUint64(&sample->period);
    239   }
    240 
    241   // { struct read_format    values;   } && PERF_SAMPLE_READ
    242   if (sample_fields & PERF_SAMPLE_READ) {
    243     if (attr.read_format & PERF_FORMAT_GROUP)
    244       ReadGroupReadInfo(&reader, attr.read_format, sample);
    245     else
    246       ReadReadInfo(&reader, attr.read_format, sample);
    247   }
    248 
    249   // { u64                   nr,
    250   //   u64                   ips[nr];  } && PERF_SAMPLE_CALLCHAIN
    251   if (sample_fields & PERF_SAMPLE_CALLCHAIN) {
    252     ReadCallchain(&reader, sample);
    253   }
    254 
    255   // { u32                   size;
    256   //   char                  data[size];}&& PERF_SAMPLE_RAW
    257   if (sample_fields & PERF_SAMPLE_RAW) {
    258     ReadRawData(&reader, sample);
    259   }
    260 
    261   // { u64                   nr;
    262   //   { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
    263   if (sample_fields & PERF_SAMPLE_BRANCH_STACK) {
    264     ReadBranchStack(&reader, sample);
    265   }
    266 
    267   // { u64                   abi; # enum perf_sample_regs_abi
    268   //   u64                   regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
    269   if (sample_fields & PERF_SAMPLE_REGS_USER) {
    270     VLOG(1) << "Skipping PERF_SAMPLE_REGS_USER data.";
    271     u64 abi;
    272     if (!reader.ReadUint64(&abi)) {
    273       return false;
    274     }
    275     size_t weight = abi == 0 ? 0 : __builtin_popcountll(attr.sample_regs_user);
    276     u64 regs[64];
    277     if (weight > 0 && !reader.ReadData(weight * sizeof(u64), regs)) {
    278       return false;
    279     }
    280   }
    281 
    282   // { u64                   size;
    283   //   char                  data[size];
    284   //   u64                   dyn_size; } && PERF_SAMPLE_STACK_USER
    285   if (sample_fields & PERF_SAMPLE_STACK_USER) {
    286     VLOG(1) << "Skipping PERF_SAMPLE_STACK_USER data.";
    287     u64 size;
    288     if (!reader.ReadUint64(&size)) {
    289       return false;
    290     }
    291     if (size != 0) {
    292       std::unique_ptr<char[]> data(new char[size]);
    293       if (!reader.ReadData(size, data.get())) {
    294         return false;
    295       }
    296       u64 dyn_size;
    297       reader.ReadUint64(&dyn_size);
    298     }
    299   }
    300 
    301   // { u64                   weight;   } && PERF_SAMPLE_WEIGHT
    302   if (sample_fields & PERF_SAMPLE_WEIGHT) {
    303     reader.ReadUint64(&sample->weight);
    304   }
    305 
    306   // { u64                   data_src; } && PERF_SAMPLE_DATA_SRC
    307   if (sample_fields & PERF_SAMPLE_DATA_SRC) {
    308     reader.ReadUint64(&sample->data_src);
    309   }
    310 
    311   // { u64                   transaction; } && PERF_SAMPLE_TRANSACTION
    312   if (sample_fields & PERF_SAMPLE_TRANSACTION) {
    313     reader.ReadUint64(&sample->transaction);
    314   }
    315 
    316   if (sample_fields & ~(PERF_SAMPLE_MAX - 1)) {
    317     LOG(WARNING) << "Unrecognized sample fields 0x" << std::hex
    318                  << (sample_fields & ~(PERF_SAMPLE_MAX - 1));
    319   }
    320 
    321   return reader.Tell();
    322 }
    323 
    324 // Writes sample info data data from |sample| into |event|.
    325 // |attr| is the event attribute struct, which contains info such as which
    326 // sample info fields are present.
    327 // |event| is the destination event. Its header should already be filled out.
    328 // Returns the number of bytes written or skipped.
    329 size_t WritePerfSampleToData(const struct perf_sample& sample,
    330                              const struct perf_event_attr& attr,
    331                              event_t* event) {
    332   const uint64_t* initial_array_ptr = reinterpret_cast<const uint64_t*>(event);
    333 
    334   uint64_t offset = SampleInfoReader::GetPerfSampleDataOffset(*event);
    335   uint64_t* array =
    336       reinterpret_cast<uint64_t*>(event) + offset / sizeof(uint64_t);
    337 
    338   if (!(event->header.type == PERF_RECORD_SAMPLE || attr.sample_id_all)) {
    339     return offset;
    340   }
    341 
    342   uint64_t sample_fields = SampleInfoReader::GetSampleFieldsForEventType(
    343       event->header.type, attr.sample_type);
    344 
    345   union {
    346     uint32_t val32[sizeof(uint64_t) / sizeof(uint32_t)];
    347     uint64_t val64;
    348   };
    349 
    350   // See notes at the top of ReadPerfSampleFromData regarding the structure
    351   // of PERF_RECORD_SAMPLE, sample_id, and PERF_SAMPLE_IDENTIFIER, as they
    352   // all apply here as well.
    353 
    354   // PERF_SAMPLE_IDENTIFIER is in a different location depending on
    355   // if this is a SAMPLE event or the sample_id of another event.
    356   if (event->header.type == PERF_RECORD_SAMPLE) {
    357     // { u64                   id;       } && PERF_SAMPLE_IDENTIFIER
    358     if (sample_fields & PERF_SAMPLE_IDENTIFIER) {
    359       *array++ = sample.id;
    360     }
    361   }
    362 
    363   // { u64                   ip;       } && PERF_SAMPLE_IP
    364   if (sample_fields & PERF_SAMPLE_IP) {
    365     *array++ = sample.ip;
    366   }
    367 
    368   // { u32                   pid, tid; } && PERF_SAMPLE_TID
    369   if (sample_fields & PERF_SAMPLE_TID) {
    370     val32[0] = sample.pid;
    371     val32[1] = sample.tid;
    372     *array++ = val64;
    373   }
    374 
    375   // { u64                   time;     } && PERF_SAMPLE_TIME
    376   if (sample_fields & PERF_SAMPLE_TIME) {
    377     *array++ = sample.time;
    378   }
    379 
    380   // { u64                   addr;     } && PERF_SAMPLE_ADDR
    381   if (sample_fields & PERF_SAMPLE_ADDR) {
    382     *array++ = sample.addr;
    383   }
    384 
    385   // { u64                   id;       } && PERF_SAMPLE_ID
    386   if (sample_fields & PERF_SAMPLE_ID) {
    387     *array++ = sample.id;
    388   }
    389 
    390   // { u64                   stream_id;} && PERF_SAMPLE_STREAM_ID
    391   if (sample_fields & PERF_SAMPLE_STREAM_ID) {
    392     *array++ = sample.stream_id;
    393   }
    394 
    395   // { u32                   cpu, res; } && PERF_SAMPLE_CPU
    396   if (sample_fields & PERF_SAMPLE_CPU) {
    397     val32[0] = sample.cpu;
    398     // val32[1] = sample.res;  // reserved
    399     val32[1] = 0;
    400     *array++ = val64;
    401   }
    402 
    403   // This is the location of PERF_SAMPLE_IDENTIFIER in struct sample_id.
    404   if (event->header.type != PERF_RECORD_SAMPLE) {
    405     // { u64                   id;       } && PERF_SAMPLE_IDENTIFIER
    406     if (sample_fields & PERF_SAMPLE_IDENTIFIER) {
    407       *array++ = sample.id;
    408     }
    409   }
    410 
    411   //
    412   // The remaining fields are only in PERF_RECORD_SAMPLE
    413   //
    414 
    415   // { u64                   period;   } && PERF_SAMPLE_PERIOD
    416   if (sample_fields & PERF_SAMPLE_PERIOD) {
    417     *array++ = sample.period;
    418   }
    419 
    420   // { struct read_format    values;   } && PERF_SAMPLE_READ
    421   if (sample_fields & PERF_SAMPLE_READ) {
    422     if (attr.read_format & PERF_FORMAT_GROUP) {
    423       *array++ = sample.read.group.nr;
    424       if (attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
    425         *array++ = sample.read.time_enabled;
    426       if (attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
    427         *array++ = sample.read.time_running;
    428       for (size_t i = 0; i < sample.read.group.nr; i++) {
    429         *array++ = sample.read.group.values[i].value;
    430         if (attr.read_format & PERF_FORMAT_ID) *array++ = sample.read.one.id;
    431       }
    432     } else {
    433       *array++ = sample.read.one.value;
    434       if (attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
    435         *array++ = sample.read.time_enabled;
    436       if (attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
    437         *array++ = sample.read.time_running;
    438       if (attr.read_format & PERF_FORMAT_ID) *array++ = sample.read.one.id;
    439     }
    440   }
    441 
    442   // { u64                   nr,
    443   //   u64                   ips[nr];  } && PERF_SAMPLE_CALLCHAIN
    444   if (sample_fields & PERF_SAMPLE_CALLCHAIN) {
    445     if (!sample.callchain) {
    446       LOG(ERROR) << "Expecting callchain data, but none was found.";
    447     } else {
    448       *array++ = sample.callchain->nr;
    449       for (size_t i = 0; i < sample.callchain->nr; ++i)
    450         *array++ = sample.callchain->ips[i];
    451     }
    452   }
    453 
    454   // { u32                   size;
    455   //   char                  data[size];}&& PERF_SAMPLE_RAW
    456   if (sample_fields & PERF_SAMPLE_RAW) {
    457     uint32_t* ptr = reinterpret_cast<uint32_t*>(array);
    458     *ptr++ = sample.raw_size;
    459     memcpy(ptr, sample.raw_data, sample.raw_size);
    460 
    461     // Update the data read pointer after aligning to the next 64 bytes.
    462     int num_bytes = Align<uint64_t>(sizeof(sample.raw_size) + sample.raw_size);
    463     array += num_bytes / sizeof(uint64_t);
    464   }
    465 
    466   // { u64                   nr;
    467   //   { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
    468   if (sample_fields & PERF_SAMPLE_BRANCH_STACK) {
    469     if (!sample.branch_stack) {
    470       LOG(ERROR) << "Expecting branch stack data, but none was found.";
    471     } else {
    472       *array++ = sample.branch_stack->nr;
    473       for (size_t i = 0; i < sample.branch_stack->nr; ++i) {
    474         *array++ = sample.branch_stack->entries[i].from;
    475         *array++ = sample.branch_stack->entries[i].to;
    476         memcpy(array++, &sample.branch_stack->entries[i].flags,
    477                sizeof(uint64_t));
    478       }
    479     }
    480   }
    481 
    482   // { u64                   abi; # enum perf_sample_regs_abi
    483   //   u64                   regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
    484   if (sample_fields & PERF_SAMPLE_REGS_USER) {
    485     LOG(ERROR) << "PERF_SAMPLE_REGS_USER is not yet supported.";
    486     return (array - initial_array_ptr) * sizeof(uint64_t);
    487   }
    488 
    489   // { u64                   size;
    490   //   char                  data[size];
    491   //   u64                   dyn_size; } && PERF_SAMPLE_STACK_USER
    492   if (sample_fields & PERF_SAMPLE_STACK_USER) {
    493     LOG(ERROR) << "PERF_SAMPLE_STACK_USER is not yet supported.";
    494     return (array - initial_array_ptr) * sizeof(uint64_t);
    495   }
    496 
    497   // { u64                   weight;   } && PERF_SAMPLE_WEIGHT
    498   if (sample_fields & PERF_SAMPLE_WEIGHT) {
    499     *array++ = sample.weight;
    500   }
    501 
    502   // { u64                   data_src; } && PERF_SAMPLE_DATA_SRC
    503   if (sample_fields & PERF_SAMPLE_DATA_SRC) {
    504     *array++ = sample.data_src;
    505   }
    506 
    507   // { u64                   transaction; } && PERF_SAMPLE_TRANSACTION
    508   if (sample_fields & PERF_SAMPLE_TRANSACTION) {
    509     *array++ = sample.transaction;
    510   }
    511 
    512   return (array - initial_array_ptr) * sizeof(uint64_t);
    513 }
    514 
    515 }  // namespace
    516 
    517 bool SampleInfoReader::ReadPerfSampleInfo(const event_t& event,
    518                                           struct perf_sample* sample) const {
    519   CHECK(sample);
    520 
    521   if (!IsSupportedEventType(event.header.type)) {
    522     LOG(ERROR) << "Unsupported event type " << event.header.type;
    523     return false;
    524   }
    525 
    526   size_t size_read_or_skipped =
    527       ReadPerfSampleFromData(event, event_attr_, read_cross_endian_, sample);
    528 
    529   if (size_read_or_skipped != event.header.size) {
    530     LOG(ERROR) << "Read/skipped " << size_read_or_skipped << " bytes, expected "
    531                << event.header.size << " bytes.";
    532   }
    533 
    534   return (size_read_or_skipped == event.header.size);
    535 }
    536 
    537 bool SampleInfoReader::WritePerfSampleInfo(const perf_sample& sample,
    538                                            event_t* event) const {
    539   CHECK(event);
    540 
    541   if (!IsSupportedEventType(event->header.type)) {
    542     LOG(ERROR) << "Unsupported event type " << event->header.type;
    543     return false;
    544   }
    545 
    546   size_t size_written_or_skipped =
    547       WritePerfSampleToData(sample, event_attr_, event);
    548   if (size_written_or_skipped != event->header.size) {
    549     LOG(ERROR) << "Wrote/skipped " << size_written_or_skipped
    550                << " bytes, expected " << event->header.size << " bytes.";
    551   }
    552 
    553   return (size_written_or_skipped == event->header.size);
    554 }
    555 
    556 // static
    557 uint64_t SampleInfoReader::GetSampleFieldsForEventType(uint32_t event_type,
    558                                                        uint64_t sample_type) {
    559   uint64_t mask = UINT64_MAX;
    560   switch (event_type) {
    561     case PERF_RECORD_MMAP:
    562     case PERF_RECORD_LOST:
    563     case PERF_RECORD_COMM:
    564     case PERF_RECORD_EXIT:
    565     case PERF_RECORD_THROTTLE:
    566     case PERF_RECORD_UNTHROTTLE:
    567     case PERF_RECORD_FORK:
    568     case PERF_RECORD_READ:
    569     case PERF_RECORD_MMAP2:
    570     case PERF_RECORD_AUX:
    571       // See perf_event.h "struct" sample_id and sample_id_all.
    572       mask = PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_ID |
    573              PERF_SAMPLE_STREAM_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER;
    574       break;
    575     case PERF_RECORD_SAMPLE:
    576       break;
    577     default:
    578       LOG(FATAL) << "Unknown event type " << event_type;
    579   }
    580   return sample_type & mask;
    581 }
    582 
    583 // static
    584 uint64_t SampleInfoReader::GetPerfSampleDataOffset(const event_t& event) {
    585   uint64_t offset = UINT64_MAX;
    586   switch (event.header.type) {
    587     case PERF_RECORD_SAMPLE:
    588       offset = offsetof(event_t, sample.array);
    589       break;
    590     case PERF_RECORD_MMAP:
    591       offset = sizeof(event.mmap) - sizeof(event.mmap.filename) +
    592                GetUint64AlignedStringLength(event.mmap.filename);
    593       break;
    594     case PERF_RECORD_FORK:
    595     case PERF_RECORD_EXIT:
    596       offset = sizeof(event.fork);
    597       break;
    598     case PERF_RECORD_COMM:
    599       offset = sizeof(event.comm) - sizeof(event.comm.comm) +
    600                GetUint64AlignedStringLength(event.comm.comm);
    601       break;
    602     case PERF_RECORD_LOST:
    603       offset = sizeof(event.lost);
    604       break;
    605     case PERF_RECORD_THROTTLE:
    606     case PERF_RECORD_UNTHROTTLE:
    607       offset = sizeof(event.throttle);
    608       break;
    609     case PERF_RECORD_READ:
    610       offset = sizeof(event.read);
    611       break;
    612     case PERF_RECORD_MMAP2:
    613       offset = sizeof(event.mmap2) - sizeof(event.mmap2.filename) +
    614                GetUint64AlignedStringLength(event.mmap2.filename);
    615       break;
    616     case PERF_RECORD_AUX:
    617       offset = sizeof(event.aux);
    618       break;
    619     default:
    620       LOG(FATAL) << "Unknown event type " << event.header.type;
    621       break;
    622   }
    623   // Make sure the offset was valid
    624   CHECK_NE(offset, UINT64_MAX);
    625   CHECK_EQ(offset % sizeof(uint64_t), 0U);
    626   return offset;
    627 }
    628 
    629 }  // namespace quipper
    630