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 #define LOG_TAG "perf_reader"
6 
7 #include "perf_utils.h"
8 
9 #include <sys/stat.h>
10 
11 #include <cctype>
12 #include <cstddef>
13 #include <cstdlib>
14 #include <cstring>
15 #include <fstream>  // NOLINT(readability/streams)
16 #include <iomanip>
17 #include <sstream>
18 
19 #include "base/logging.h"
20 #include "base/macros.h"
21 
22 namespace {
23 
24 // Number of hex digits in a byte.
25 const int kNumHexDigitsInByte = 2;
26 
27 }  // namespace
28 
29 namespace quipper {
30 
CallocMemoryForEvent(size_t size)31 event_t* CallocMemoryForEvent(size_t size) {
32   event_t* event = reinterpret_cast<event_t*>(calloc(1, size));
33   CHECK(event);
34   return event;
35 }
36 
CallocMemoryForBuildID(size_t size)37 build_id_event* CallocMemoryForBuildID(size_t size) {
38   build_id_event* event = reinterpret_cast<build_id_event*>(calloc(1, size));
39   CHECK(event);
40   return event;
41 }
42 
HexToString(const u8 * array,size_t length)43 string HexToString(const u8* array, size_t length) {
44   // Convert the bytes to hex digits one at a time.
45   // There will be kNumHexDigitsInByte hex digits, and 1 char for NUL.
46   char buffer[kNumHexDigitsInByte + 1];
47   string result = "";
48   for (size_t i = 0; i < length; ++i) {
49     snprintf(buffer, sizeof(buffer), "%02x", array[i]);
50     result += buffer;
51   }
52   return result;
53 }
54 
StringToHex(const string & str,u8 * array,size_t length)55 bool StringToHex(const string& str, u8* array, size_t length) {
56   const int kHexRadix = 16;
57   char* err;
58   // Loop through kNumHexDigitsInByte characters at a time (to get one byte)
59   // Stop when there are no more characters, or the array has been filled.
60   for (size_t i = 0;
61        (i + 1) * kNumHexDigitsInByte <= str.size() && i < length;
62        ++i) {
63     string one_byte = str.substr(i * kNumHexDigitsInByte, kNumHexDigitsInByte);
64     array[i] = strtol(one_byte.c_str(), &err, kHexRadix);
65     if (*err)
66       return false;
67   }
68   return true;
69 }
70 
AlignSize(uint64_t size,uint32_t align_size)71 uint64_t AlignSize(uint64_t size, uint32_t align_size) {
72   return ((size + align_size - 1) / align_size) * align_size;
73 }
74 
75 // In perf data, strings are packed into the smallest number of 8-byte blocks
76 // possible, including the null terminator.
77 // e.g.
78 //    "0123"                ->  5 bytes -> packed into  8 bytes
79 //    "0123456"             ->  8 bytes -> packed into  8 bytes
80 //    "01234567"            ->  9 bytes -> packed into 16 bytes
81 //    "0123456789abcd"      -> 15 bytes -> packed into 16 bytes
82 //    "0123456789abcde"     -> 16 bytes -> packed into 16 bytes
83 //    "0123456789abcdef"    -> 17 bytes -> packed into 24 bytes
84 //
85 // Returns the size of the 8-byte-aligned memory for storing |string|.
GetUint64AlignedStringLength(const string & str)86 size_t GetUint64AlignedStringLength(const string& str) {
87   return AlignSize(str.size() + 1, sizeof(uint64_t));
88 }
89 
GetSampleFieldsForEventType(uint32_t event_type,uint64_t sample_type)90 uint64_t GetSampleFieldsForEventType(uint32_t event_type,
91                                      uint64_t sample_type) {
92   uint64_t mask = kuint64max;
93   switch (event_type) {
94   case PERF_RECORD_MMAP:
95   case PERF_RECORD_LOST:
96   case PERF_RECORD_COMM:
97   case PERF_RECORD_EXIT:
98   case PERF_RECORD_THROTTLE:
99   case PERF_RECORD_UNTHROTTLE:
100   case PERF_RECORD_FORK:
101   case PERF_RECORD_READ:
102   case PERF_RECORD_MMAP2:
103     // See perf_event.h "struct" sample_id and sample_id_all.
104     mask = PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_ID |
105            PERF_SAMPLE_STREAM_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER;
106     break;
107   case PERF_RECORD_SAMPLE:
108   case SIMPLE_PERF_RECORD_KERNEL_SYMBOL:
109     break;
110   default:
111     LOG(FATAL) << "Unknown event type " << event_type;
112   }
113   return sample_type & mask;
114 }
115 
GetPerfSampleDataOffset(const event_t & event)116 uint64_t GetPerfSampleDataOffset(const event_t& event) {
117   uint64_t offset = kuint64max;
118   switch (event.header.type) {
119   case PERF_RECORD_SAMPLE:
120     offset = offsetof(event_t, sample.array);
121     break;
122   case PERF_RECORD_MMAP:
123     offset = sizeof(event.mmap) - sizeof(event.mmap.filename) +
124              GetUint64AlignedStringLength(event.mmap.filename);
125     break;
126   case PERF_RECORD_FORK:
127   case PERF_RECORD_EXIT:
128     offset = sizeof(event.fork);
129     break;
130   case PERF_RECORD_COMM:
131     offset = sizeof(event.comm) - sizeof(event.comm.comm) +
132              GetUint64AlignedStringLength(event.comm.comm);
133     break;
134   case PERF_RECORD_LOST:
135     offset = sizeof(event.lost);
136     break;
137   case PERF_RECORD_READ:
138     offset = sizeof(event.read);
139     break;
140   case PERF_RECORD_MMAP2:
141     offset = sizeof(event.mmap2) - sizeof(event.mmap2.filename) +
142              GetUint64AlignedStringLength(event.mmap2.filename);
143     break;
144   case SIMPLE_PERF_RECORD_KERNEL_SYMBOL:
145     offset = 0;
146     break;
147   default:
148     LOG(FATAL) << "Unknown/unsupported event type " << event.header.type;
149     break;
150   }
151   // Make sure the offset was valid
152   CHECK_NE(offset, kuint64max);
153   CHECK_EQ(offset % sizeof(uint64_t), 0U);
154   return offset;
155 }
156 
ReadFileToData(const string & filename,std::vector<char> * data)157 bool ReadFileToData(const string& filename, std::vector<char>* data) {
158   std::ifstream in(filename.c_str(), std::ios::binary);
159   if (!in.good()) {
160     LOG(ERROR) << "Failed to open file " << filename;
161     return false;
162   }
163   in.seekg(0, in.end);
164   size_t length = in.tellg();
165   in.seekg(0, in.beg);
166   data->resize(length);
167 
168   in.read(&(*data)[0], length);
169 
170   if (!in.good()) {
171     LOG(ERROR) << "Error reading from file " << filename;
172     return false;
173   }
174   return true;
175 }
176 
WriteDataToFile(const std::vector<char> & data,const string & filename)177 bool WriteDataToFile(const std::vector<char>& data, const string& filename) {
178   std::ofstream out(filename.c_str(), std::ios::binary);
179   out.seekp(0, std::ios::beg);
180   out.write(&data[0], data.size());
181   return out.good();
182 }
183 
184 }  // namespace quipper
185