• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "record_file.h"
18 
19 #include <fcntl.h>
20 #include <string.h>
21 #include <set>
22 #include <vector>
23 
24 #include <android-base/logging.h>
25 
26 #include "event_attr.h"
27 #include "record.h"
28 #include "utils.h"
29 
30 using namespace PerfFileFormat;
31 
32 namespace PerfFileFormat {
33 
34 static const std::map<int, std::string> feature_name_map = {
35     {FEAT_TRACING_DATA, "tracing_data"},
36     {FEAT_BUILD_ID, "build_id"},
37     {FEAT_HOSTNAME, "hostname"},
38     {FEAT_OSRELEASE, "osrelease"},
39     {FEAT_VERSION, "version"},
40     {FEAT_ARCH, "arch"},
41     {FEAT_NRCPUS, "nrcpus"},
42     {FEAT_CPUDESC, "cpudesc"},
43     {FEAT_CPUID, "cpuid"},
44     {FEAT_TOTAL_MEM, "total_mem"},
45     {FEAT_CMDLINE, "cmdline"},
46     {FEAT_EVENT_DESC, "event_desc"},
47     {FEAT_CPU_TOPOLOGY, "cpu_topology"},
48     {FEAT_NUMA_TOPOLOGY, "numa_topology"},
49     {FEAT_BRANCH_STACK, "branch_stack"},
50     {FEAT_PMU_MAPPINGS, "pmu_mappings"},
51     {FEAT_GROUP_DESC, "group_desc"},
52     {FEAT_FILE, "file"},
53     {FEAT_META_INFO, "meta_info"},
54 };
55 
GetFeatureName(int feature_id)56 std::string GetFeatureName(int feature_id) {
57   auto it = feature_name_map.find(feature_id);
58   return it == feature_name_map.end() ? "" : it->second;
59 }
60 
GetFeatureId(const std::string & feature_name)61 int GetFeatureId(const std::string& feature_name) {
62   for (auto& pair : feature_name_map) {
63     if (pair.second == feature_name) {
64       return pair.first;
65     }
66   }
67   return -1;
68 }
69 
70 } // namespace PerfFileFormat
71 
CreateInstance(const std::string & filename)72 std::unique_ptr<RecordFileReader> RecordFileReader::CreateInstance(const std::string& filename) {
73   std::string mode = std::string("rb") + CLOSE_ON_EXEC_MODE;
74   FILE* fp = fopen(filename.c_str(), mode.c_str());
75   if (fp == nullptr) {
76     PLOG(ERROR) << "failed to open record file '" << filename << "'";
77     return nullptr;
78   }
79   auto reader = std::unique_ptr<RecordFileReader>(new RecordFileReader(filename, fp));
80   if (!reader->ReadHeader() || !reader->ReadAttrSection() ||
81       !reader->ReadFeatureSectionDescriptors()) {
82     return nullptr;
83   }
84   return reader;
85 }
86 
RecordFileReader(const std::string & filename,FILE * fp)87 RecordFileReader::RecordFileReader(const std::string& filename, FILE* fp)
88     : filename_(filename), record_fp_(fp), event_id_pos_in_sample_records_(0),
89       event_id_reverse_pos_in_non_sample_records_(0), read_record_size_(0) {
90 }
91 
~RecordFileReader()92 RecordFileReader::~RecordFileReader() {
93   if (record_fp_ != nullptr) {
94     Close();
95   }
96 }
97 
Close()98 bool RecordFileReader::Close() {
99   bool result = true;
100   if (fclose(record_fp_) != 0) {
101     PLOG(ERROR) << "failed to close record file '" << filename_ << "'";
102     result = false;
103   }
104   record_fp_ = nullptr;
105   return result;
106 }
107 
ReadHeader()108 bool RecordFileReader::ReadHeader() {
109   if (!Read(&header_, sizeof(header_))) {
110     return false;
111   }
112   if (memcmp(header_.magic, PERF_MAGIC, sizeof(header_.magic)) != 0) {
113     LOG(ERROR) << filename_ << " is not a valid profiling record file.";
114     return false;
115   }
116   return true;
117 }
118 
ReadAttrSection()119 bool RecordFileReader::ReadAttrSection() {
120   size_t attr_count = header_.attrs.size / header_.attr_size;
121   if (header_.attr_size != sizeof(FileAttr)) {
122     LOG(DEBUG) << "attr size (" << header_.attr_size << ") in " << filename_
123                  << " doesn't match expected size (" << sizeof(FileAttr) << ")";
124   }
125   if (attr_count == 0) {
126     LOG(ERROR) << "no attr in file " << filename_;
127     return false;
128   }
129   if (fseek(record_fp_, header_.attrs.offset, SEEK_SET) != 0) {
130     PLOG(ERROR) << "fseek() failed";
131     return false;
132   }
133   for (size_t i = 0; i < attr_count; ++i) {
134     std::vector<char> buf(header_.attr_size);
135     if (!Read(buf.data(), buf.size())) {
136       return false;
137     }
138     // The size of perf_event_attr is changing between different linux kernel versions.
139     // Make sure we copy correct data to memory.
140     FileAttr attr;
141     memset(&attr, 0, sizeof(attr));
142     size_t section_desc_size = sizeof(attr.ids);
143     size_t perf_event_attr_size = header_.attr_size - section_desc_size;
144     memcpy(&attr.attr, &buf[0], std::min(sizeof(attr.attr), perf_event_attr_size));
145     memcpy(&attr.ids, &buf[perf_event_attr_size], section_desc_size);
146     file_attrs_.push_back(attr);
147   }
148   if (file_attrs_.size() > 1) {
149     std::vector<perf_event_attr> attrs;
150     for (const auto& file_attr : file_attrs_) {
151       attrs.push_back(file_attr.attr);
152     }
153     if (!GetCommonEventIdPositionsForAttrs(attrs, &event_id_pos_in_sample_records_,
154                                                &event_id_reverse_pos_in_non_sample_records_)) {
155       return false;
156     }
157   }
158   for (size_t i = 0; i < file_attrs_.size(); ++i) {
159     std::vector<uint64_t> ids;
160     if (!ReadIdsForAttr(file_attrs_[i], &ids)) {
161       return false;
162     }
163     event_ids_for_file_attrs_.push_back(ids);
164     for (auto id : ids) {
165       event_id_to_attr_map_[id] = i;
166     }
167   }
168   return true;
169 }
170 
ReadFeatureSectionDescriptors()171 bool RecordFileReader::ReadFeatureSectionDescriptors() {
172   std::vector<int> features;
173   for (size_t i = 0; i < sizeof(header_.features); ++i) {
174     for (size_t j = 0; j < 8; ++j) {
175       if (header_.features[i] & (1 << j)) {
176         features.push_back(i * 8 + j);
177       }
178     }
179   }
180   uint64_t feature_section_offset = header_.data.offset + header_.data.size;
181   if (fseek(record_fp_, feature_section_offset, SEEK_SET) != 0) {
182     PLOG(ERROR) << "fseek() failed";
183     return false;
184   }
185   for (const auto& id : features) {
186     SectionDesc desc;
187     if (!Read(&desc, sizeof(desc))) {
188       return false;
189     }
190     feature_section_descriptors_.emplace(id, desc);
191   }
192   return true;
193 }
194 
ReadIdsForAttr(const FileAttr & attr,std::vector<uint64_t> * ids)195 bool RecordFileReader::ReadIdsForAttr(const FileAttr& attr, std::vector<uint64_t>* ids) {
196   size_t id_count = attr.ids.size / sizeof(uint64_t);
197   if (fseek(record_fp_, attr.ids.offset, SEEK_SET) != 0) {
198     PLOG(ERROR) << "fseek() failed";
199     return false;
200   }
201   ids->resize(id_count);
202   if (!Read(ids->data(), attr.ids.size)) {
203     return false;
204   }
205   return true;
206 }
207 
ReadDataSection(const std::function<bool (std::unique_ptr<Record>)> & callback)208 bool RecordFileReader::ReadDataSection(
209     const std::function<bool(std::unique_ptr<Record>)>& callback) {
210   std::unique_ptr<Record> record;
211   while (ReadRecord(record)) {
212     if (record == nullptr) {
213       return true;
214     }
215     if (!callback(std::move(record))) {
216       return false;
217     }
218   }
219   return false;
220 }
221 
ReadRecord(std::unique_ptr<Record> & record)222 bool RecordFileReader::ReadRecord(std::unique_ptr<Record>& record) {
223   if (read_record_size_ == 0) {
224     if (fseek(record_fp_, header_.data.offset, SEEK_SET) != 0) {
225       PLOG(ERROR) << "fseek() failed";
226       return false;
227     }
228   }
229   record = nullptr;
230   if (read_record_size_ < header_.data.size) {
231     record = ReadRecord(&read_record_size_);
232     if (record == nullptr) {
233       return false;
234     }
235     if (record->type() == SIMPLE_PERF_RECORD_EVENT_ID) {
236       ProcessEventIdRecord(*static_cast<EventIdRecord*>(record.get()));
237     }
238   }
239   return true;
240 }
241 
ReadRecord(uint64_t * nbytes_read)242 std::unique_ptr<Record> RecordFileReader::ReadRecord(uint64_t* nbytes_read) {
243   char header_buf[Record::header_size()];
244   if (!Read(header_buf, Record::header_size())) {
245     return nullptr;
246   }
247   RecordHeader header(header_buf);
248   std::unique_ptr<char[]> p;
249   if (header.type == SIMPLE_PERF_RECORD_SPLIT) {
250     // Read until meeting a RECORD_SPLIT_END record.
251     std::vector<char> buf;
252     size_t cur_size = 0;
253     char header_buf[Record::header_size()];
254     while (header.type == SIMPLE_PERF_RECORD_SPLIT) {
255       size_t bytes_to_read = header.size - Record::header_size();
256       buf.resize(cur_size + bytes_to_read);
257       if (!Read(&buf[cur_size], bytes_to_read)) {
258         return nullptr;
259       }
260       cur_size += bytes_to_read;
261       *nbytes_read += header.size;
262       if (!Read(header_buf, Record::header_size())) {
263         return nullptr;
264       }
265       header = RecordHeader(header_buf);
266     }
267     if (header.type != SIMPLE_PERF_RECORD_SPLIT_END) {
268       LOG(ERROR) << "SPLIT records are not followed by a SPLIT_END record.";
269       return nullptr;
270     }
271     *nbytes_read += header.size;
272     header = RecordHeader(buf.data());
273     p.reset(new char[header.size]);
274     memcpy(p.get(), buf.data(), buf.size());
275   } else {
276     p.reset(new char[header.size]);
277     memcpy(p.get(), header_buf, Record::header_size());
278     if (header.size > Record::header_size()) {
279       if (!Read(p.get() + Record::header_size(), header.size - Record::header_size())) {
280         return nullptr;
281       }
282     }
283     *nbytes_read += header.size;
284   }
285 
286   const perf_event_attr* attr = &file_attrs_[0].attr;
287   if (file_attrs_.size() > 1 && header.type < PERF_RECORD_USER_DEFINED_TYPE_START) {
288     bool has_event_id = false;
289     uint64_t event_id;
290     if (header.type == PERF_RECORD_SAMPLE) {
291       if (header.size > event_id_pos_in_sample_records_ + sizeof(uint64_t)) {
292         has_event_id = true;
293         event_id = *reinterpret_cast<uint64_t*>(p.get() + event_id_pos_in_sample_records_);
294       }
295     } else {
296       if (header.size > event_id_reverse_pos_in_non_sample_records_) {
297         has_event_id = true;
298         event_id = *reinterpret_cast<uint64_t*>(p.get() + header.size - event_id_reverse_pos_in_non_sample_records_);
299       }
300     }
301     if (has_event_id) {
302       auto it = event_id_to_attr_map_.find(event_id);
303       if (it != event_id_to_attr_map_.end()) {
304         attr = &file_attrs_[it->second].attr;
305       }
306     }
307   }
308   return ReadRecordFromOwnedBuffer(*attr, header.type, p.release());
309 }
310 
Read(void * buf,size_t len)311 bool RecordFileReader::Read(void* buf, size_t len) {
312   if (len != 0 && fread(buf, len, 1, record_fp_) != 1) {
313     PLOG(FATAL) << "failed to read file " << filename_;
314     return false;
315   }
316   return true;
317 }
318 
ProcessEventIdRecord(const EventIdRecord & r)319 void RecordFileReader::ProcessEventIdRecord(const EventIdRecord& r) {
320   for (size_t i = 0; i < r.count; ++i) {
321     event_ids_for_file_attrs_[r.data[i].attr_id].push_back(r.data[i].event_id);
322     event_id_to_attr_map_[r.data[i].event_id] = r.data[i].attr_id;
323   }
324 }
325 
GetAttrIndexOfRecord(const Record * record)326 size_t RecordFileReader::GetAttrIndexOfRecord(const Record* record) {
327   auto it = event_id_to_attr_map_.find(record->Id());
328   if (it != event_id_to_attr_map_.end()) {
329     return it->second;
330   }
331   return 0;
332 }
333 
ReadFeatureSection(int feature,std::vector<char> * data)334 bool RecordFileReader::ReadFeatureSection(int feature, std::vector<char>* data) {
335   const std::map<int, SectionDesc>& section_map = FeatureSectionDescriptors();
336   auto it = section_map.find(feature);
337   if (it == section_map.end()) {
338     return false;
339   }
340   SectionDesc section = it->second;
341   data->resize(section.size);
342   if (section.size == 0) {
343     return true;
344   }
345   if (fseek(record_fp_, section.offset, SEEK_SET) != 0) {
346     PLOG(ERROR) << "fseek() failed";
347     return false;
348   }
349   if (!Read(data->data(), data->size())) {
350     return false;
351   }
352   return true;
353 }
354 
ReadCmdlineFeature()355 std::vector<std::string> RecordFileReader::ReadCmdlineFeature() {
356   std::vector<char> buf;
357   if (!ReadFeatureSection(FEAT_CMDLINE, &buf)) {
358     return std::vector<std::string>();
359   }
360   const char* p = buf.data();
361   const char* end = buf.data() + buf.size();
362   std::vector<std::string> cmdline;
363   uint32_t arg_count;
364   MoveFromBinaryFormat(arg_count, p);
365   CHECK_LE(p, end);
366   for (size_t i = 0; i < arg_count; ++i) {
367     uint32_t len;
368     MoveFromBinaryFormat(len, p);
369     CHECK_LE(p + len, end);
370     cmdline.push_back(p);
371     p += len;
372   }
373   return cmdline;
374 }
375 
ReadBuildIdFeature()376 std::vector<BuildIdRecord> RecordFileReader::ReadBuildIdFeature() {
377   std::vector<char> buf;
378   if (!ReadFeatureSection(FEAT_BUILD_ID, &buf)) {
379     return std::vector<BuildIdRecord>();
380   }
381   const char* p = buf.data();
382   const char* end = buf.data() + buf.size();
383   std::vector<BuildIdRecord> result;
384   while (p < end) {
385     auto header = reinterpret_cast<const perf_event_header*>(p);
386     CHECK_LE(p + header->size, end);
387     char* binary = new char[header->size];
388     memcpy(binary, p, header->size);
389     p += header->size;
390     BuildIdRecord record(binary);
391     record.OwnBinary();
392     // Set type explicitly as the perf.data produced by perf doesn't set it.
393     record.SetTypeAndMisc(PERF_RECORD_BUILD_ID, record.misc());
394     result.push_back(std::move(record));
395   }
396   return result;
397 }
398 
ReadFeatureString(int feature)399 std::string RecordFileReader::ReadFeatureString(int feature) {
400   std::vector<char> buf;
401   if (!ReadFeatureSection(feature, &buf)) {
402     return std::string();
403   }
404   const char* p = buf.data();
405   const char* end = buf.data() + buf.size();
406   uint32_t len;
407   MoveFromBinaryFormat(len, p);
408   CHECK_LE(p + len, end);
409   return p;
410 }
411 
ReadFileFeature(size_t & read_pos,std::string * file_path,uint32_t * file_type,uint64_t * min_vaddr,uint64_t * file_offset_of_min_vaddr,std::vector<Symbol> * symbols,std::vector<uint64_t> * dex_file_offsets)412 bool RecordFileReader::ReadFileFeature(size_t& read_pos,
413                                        std::string* file_path,
414                                        uint32_t* file_type,
415                                        uint64_t* min_vaddr,
416                                        uint64_t* file_offset_of_min_vaddr,
417                                        std::vector<Symbol>* symbols,
418                                        std::vector<uint64_t>* dex_file_offsets) {
419   auto it = feature_section_descriptors_.find(FEAT_FILE);
420   if (it == feature_section_descriptors_.end()) {
421     return false;
422   }
423   if (read_pos >= it->second.size) {
424     return false;
425   }
426   if (read_pos == 0) {
427     if (fseek(record_fp_, it->second.offset, SEEK_SET) != 0) {
428       PLOG(ERROR) << "fseek() failed";
429       return false;
430     }
431   }
432   uint32_t size;
433   if (!Read(&size, 4)) {
434     return false;
435   }
436   std::vector<char> buf(size);
437   if (!Read(buf.data(), size)) {
438     return false;
439   }
440   read_pos += 4 + size;
441   const char* p = buf.data();
442   *file_path = p;
443   p += file_path->size() + 1;
444   MoveFromBinaryFormat(*file_type, p);
445   MoveFromBinaryFormat(*min_vaddr, p);
446   uint32_t symbol_count;
447   MoveFromBinaryFormat(symbol_count, p);
448   symbols->clear();
449   symbols->reserve(symbol_count);
450   for (uint32_t i = 0; i < symbol_count; ++i) {
451     uint64_t start_vaddr;
452     uint32_t len;
453     MoveFromBinaryFormat(start_vaddr, p);
454     MoveFromBinaryFormat(len, p);
455     std::string name = p;
456     p += name.size() + 1;
457     symbols->emplace_back(name, start_vaddr, len);
458   }
459   dex_file_offsets->clear();
460   if (*file_type == static_cast<uint32_t>(DSO_DEX_FILE)) {
461     uint32_t offset_count;
462     MoveFromBinaryFormat(offset_count, p);
463     dex_file_offsets->resize(offset_count);
464     MoveFromBinaryFormat(dex_file_offsets->data(), offset_count, p);
465   }
466   *file_offset_of_min_vaddr = std::numeric_limits<uint64_t>::max();
467   if (*file_type == DSO_ELF_FILE && static_cast<size_t>(p - buf.data()) < size) {
468     MoveFromBinaryFormat(*file_offset_of_min_vaddr, p);
469   }
470   CHECK_EQ(size, static_cast<size_t>(p - buf.data()));
471   return true;
472 }
473 
ReadMetaInfoFeature(std::unordered_map<std::string,std::string> * info_map)474 bool RecordFileReader::ReadMetaInfoFeature(std::unordered_map<std::string, std::string>* info_map) {
475   std::vector<char> buf;
476   if (!ReadFeatureSection(FEAT_META_INFO, &buf)) {
477     return false;
478   }
479   const char* p = buf.data();
480   const char* end = buf.data() + buf.size();
481   while (p < end) {
482     const char* key = p;
483     const char* value = key + strlen(key) + 1;
484     CHECK(value < end);
485     (*info_map)[p] = value;
486     p = value + strlen(value) + 1;
487   }
488   return true;
489 }
490 
LoadBuildIdAndFileFeatures(ThreadTree & thread_tree)491 void RecordFileReader::LoadBuildIdAndFileFeatures(ThreadTree& thread_tree) {
492   std::vector<BuildIdRecord> records = ReadBuildIdFeature();
493   std::vector<std::pair<std::string, BuildId>> build_ids;
494   for (auto& r : records) {
495     build_ids.push_back(std::make_pair(r.filename, r.build_id));
496   }
497   Dso::SetBuildIds(build_ids);
498 
499   if (HasFeature(PerfFileFormat::FEAT_FILE)) {
500     std::string file_path;
501     uint32_t file_type;
502     uint64_t min_vaddr;
503     uint64_t file_offset_of_min_vaddr;
504     std::vector<Symbol> symbols;
505     std::vector<uint64_t> dex_file_offsets;
506     size_t read_pos = 0;
507     while (ReadFileFeature(read_pos, &file_path, &file_type, &min_vaddr, &file_offset_of_min_vaddr,
508                            &symbols, &dex_file_offsets)) {
509       thread_tree.AddDsoInfo(file_path, file_type, min_vaddr, file_offset_of_min_vaddr, &symbols,
510                              dex_file_offsets);
511     }
512   }
513 }
514 
DataSection()515 std::vector<std::unique_ptr<Record>> RecordFileReader::DataSection() {
516   std::vector<std::unique_ptr<Record>> records;
517   ReadDataSection([&](std::unique_ptr<Record> record) {
518     records.push_back(std::move(record));
519     return true;
520   });
521   return records;
522 }
523