2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "record_file.h"
24 #include <android-base/logging.h>
26 #include "event_attr.h"
30 using namespace PerfFileFormat;
32 std::unique_ptr<RecordFileReader> RecordFileReader::CreateInstance(const std::string& filename) {
33 std::string mode = std::string("rb") + CLOSE_ON_EXEC_MODE;
34 FILE* fp = fopen(filename.c_str(), mode.c_str());
36 PLOG(ERROR) << "failed to open record file '" << filename << "'";
39 auto reader = std::unique_ptr<RecordFileReader>(new RecordFileReader(filename, fp));
40 if (!reader->ReadHeader() || !reader->ReadAttrSection() ||
41 !reader->ReadFeatureSectionDescriptors()) {
47 RecordFileReader::RecordFileReader(const std::string& filename, FILE* fp)
48 : filename_(filename), record_fp_(fp), event_id_pos_in_sample_records_(0),
49 event_id_reverse_pos_in_non_sample_records_(0) {
52 RecordFileReader::~RecordFileReader() {
53 if (record_fp_ != nullptr) {
58 bool RecordFileReader::Close() {
60 if (fclose(record_fp_) != 0) {
61 PLOG(ERROR) << "failed to close record file '" << filename_ << "'";
68 bool RecordFileReader::ReadHeader() {
69 return Read(&header_, sizeof(header_));
72 bool RecordFileReader::ReadAttrSection() {
73 size_t attr_count = header_.attrs.size / header_.attr_size;
74 if (header_.attr_size != sizeof(FileAttr)) {
75 LOG(DEBUG) << "attr size (" << header_.attr_size << ") in " << filename_
76 << " doesn't match expected size (" << sizeof(FileAttr) << ")";
78 if (attr_count == 0) {
79 LOG(ERROR) << "no attr in file " << filename_;
82 if (fseek(record_fp_, header_.attrs.offset, SEEK_SET) != 0) {
83 PLOG(ERROR) << "fseek() failed";
86 for (size_t i = 0; i < attr_count; ++i) {
87 std::vector<char> buf(header_.attr_size);
88 if (!Read(buf.data(), buf.size())) {
91 // The size of perf_event_attr is changing between different linux kernel versions.
92 // Make sure we copy correct data to memory.
94 memset(&attr, 0, sizeof(attr));
95 size_t section_desc_size = sizeof(attr.ids);
96 size_t perf_event_attr_size = header_.attr_size - section_desc_size;
97 memcpy(&attr.attr, &buf[0], std::min(sizeof(attr.attr), perf_event_attr_size));
98 memcpy(&attr.ids, &buf[perf_event_attr_size], section_desc_size);
99 file_attrs_.push_back(attr);
101 if (file_attrs_.size() > 1) {
102 std::vector<perf_event_attr> attrs;
103 for (const auto& file_attr : file_attrs_) {
104 attrs.push_back(file_attr.attr);
106 if (!GetCommonEventIdPositionsForAttrs(attrs, &event_id_pos_in_sample_records_,
107 &event_id_reverse_pos_in_non_sample_records_)) {
111 for (size_t i = 0; i < file_attrs_.size(); ++i) {
112 std::vector<uint64_t> ids;
113 if (!ReadIdsForAttr(file_attrs_[i], &ids)) {
116 event_ids_for_file_attrs_.push_back(ids);
117 for (auto id : ids) {
118 event_id_to_attr_map_[id] = &file_attrs_[i].attr;
124 bool RecordFileReader::ReadFeatureSectionDescriptors() {
125 std::vector<int> features;
126 for (size_t i = 0; i < sizeof(header_.features); ++i) {
127 for (size_t j = 0; j < 8; ++j) {
128 if (header_.features[i] & (1 << j)) {
129 features.push_back(i * 8 + j);
133 uint64_t feature_section_offset = header_.data.offset + header_.data.size;
134 if (fseek(record_fp_, feature_section_offset, SEEK_SET) != 0) {
135 PLOG(ERROR) << "fseek() failed";
138 for (const auto& id : features) {
140 if (!Read(&desc, sizeof(desc))) {
143 feature_section_descriptors_.emplace(id, desc);
148 bool RecordFileReader::ReadIdsForAttr(const FileAttr& attr, std::vector<uint64_t>* ids) {
149 size_t id_count = attr.ids.size / sizeof(uint64_t);
150 if (fseek(record_fp_, attr.ids.offset, SEEK_SET) != 0) {
151 PLOG(ERROR) << "fseek() failed";
154 ids->resize(id_count);
155 if (!Read(ids->data(), attr.ids.size)) {
161 bool RecordFileReader::ReadDataSection(
162 const std::function<bool(std::unique_ptr<Record>)>& callback, bool sorted) {
163 if (fseek(record_fp_, header_.data.offset, SEEK_SET) != 0) {
164 PLOG(ERROR) << "fseek() failed";
167 bool has_timestamp = true;
168 for (const auto& attr : file_attrs_) {
169 if (!IsTimestampSupported(attr.attr)) {
170 has_timestamp = false;
174 RecordCache cache(has_timestamp);
175 for (size_t nbytes_read = 0; nbytes_read < header_.data.size;) {
176 std::unique_ptr<Record> record = ReadRecord(&nbytes_read);
177 if (record == nullptr) {
180 if (record->type() == SIMPLE_PERF_RECORD_EVENT_ID) {
181 ProcessEventIdRecord(*static_cast<EventIdRecord*>(record.get()));
184 cache.Push(std::move(record));
185 record = cache.Pop();
186 if (record != nullptr) {
187 if (!callback(std::move(record))) {
192 if (!callback(std::move(record))) {
197 std::vector<std::unique_ptr<Record>> records = cache.PopAll();
198 for (auto& record : records) {
199 if (!callback(std::move(record))) {
206 std::unique_ptr<Record> RecordFileReader::ReadRecord(size_t* nbytes_read) {
207 char header_buf[Record::header_size()];
208 if (!Read(header_buf, Record::header_size())) {
211 RecordHeader header(header_buf);
212 std::unique_ptr<char[]> p;
213 if (header.type == SIMPLE_PERF_RECORD_SPLIT) {
214 // Read until meeting a RECORD_SPLIT_END record.
215 std::vector<char> buf;
217 char header_buf[Record::header_size()];
218 while (header.type == SIMPLE_PERF_RECORD_SPLIT) {
219 size_t bytes_to_read = header.size - Record::header_size();
220 buf.resize(cur_size + bytes_to_read);
221 if (!Read(&buf[cur_size], bytes_to_read)) {
224 cur_size += bytes_to_read;
225 *nbytes_read += header.size;
226 if (!Read(header_buf, Record::header_size())) {
229 header = RecordHeader(header_buf);
231 if (header.type != SIMPLE_PERF_RECORD_SPLIT_END) {
232 LOG(ERROR) << "SPLIT records are not followed by a SPLIT_END record.";
235 *nbytes_read += header.size;
236 header = RecordHeader(buf.data());
237 p.reset(new char[header.size]);
238 memcpy(p.get(), buf.data(), buf.size());
240 p.reset(new char[header.size]);
241 memcpy(p.get(), header_buf, Record::header_size());
242 if (header.size > Record::header_size()) {
243 if (!Read(p.get() + Record::header_size(), header.size - Record::header_size())) {
247 *nbytes_read += header.size;
250 const perf_event_attr* attr = &file_attrs_[0].attr;
251 if (file_attrs_.size() > 1 && header.type < PERF_RECORD_USER_DEFINED_TYPE_START) {
252 bool has_event_id = false;
254 if (header.type == PERF_RECORD_SAMPLE) {
255 if (header.size > event_id_pos_in_sample_records_ + sizeof(uint64_t)) {
257 event_id = *reinterpret_cast<uint64_t*>(p.get() + event_id_pos_in_sample_records_);
260 if (header.size > event_id_reverse_pos_in_non_sample_records_) {
262 event_id = *reinterpret_cast<uint64_t*>(p.get() + header.size - event_id_reverse_pos_in_non_sample_records_);
266 auto it = event_id_to_attr_map_.find(event_id);
267 if (it != event_id_to_attr_map_.end()) {
272 return ReadRecordFromOwnedBuffer(*attr, header.type, p.release());
275 bool RecordFileReader::Read(void* buf, size_t len) {
276 if (len != 0 && fread(buf, len, 1, record_fp_) != 1) {
277 PLOG(FATAL) << "failed to read file " << filename_;
283 void RecordFileReader::ProcessEventIdRecord(const EventIdRecord& r) {
284 for (size_t i = 0; i < r.count; ++i) {
285 event_ids_for_file_attrs_[r.data[i].attr_id].push_back(r.data[i].event_id);
286 event_id_to_attr_map_[r.data[i].event_id] =
287 &file_attrs_[r.data[i].attr_id].attr;
291 bool RecordFileReader::ReadFeatureSection(int feature, std::vector<char>* data) {
292 const std::map<int, SectionDesc>& section_map = FeatureSectionDescriptors();
293 auto it = section_map.find(feature);
294 if (it == section_map.end()) {
297 SectionDesc section = it->second;
298 data->resize(section.size);
299 if (section.size == 0) {
302 if (fseek(record_fp_, section.offset, SEEK_SET) != 0) {
303 PLOG(ERROR) << "fseek() failed";
306 if (!Read(data->data(), data->size())) {
312 std::vector<std::string> RecordFileReader::ReadCmdlineFeature() {
313 std::vector<char> buf;
314 if (!ReadFeatureSection(FEAT_CMDLINE, &buf)) {
315 return std::vector<std::string>();
317 const char* p = buf.data();
318 const char* end = buf.data() + buf.size();
319 std::vector<std::string> cmdline;
321 MoveFromBinaryFormat(arg_count, p);
323 for (size_t i = 0; i < arg_count; ++i) {
325 MoveFromBinaryFormat(len, p);
326 CHECK_LE(p + len, end);
327 cmdline.push_back(p);
333 std::vector<BuildIdRecord> RecordFileReader::ReadBuildIdFeature() {
334 std::vector<char> buf;
335 if (!ReadFeatureSection(FEAT_BUILD_ID, &buf)) {
336 return std::vector<BuildIdRecord>();
338 const char* p = buf.data();
339 const char* end = buf.data() + buf.size();
340 std::vector<BuildIdRecord> result;
342 BuildIdRecord record(p);
343 // Set type explicitly as the perf.data produced by perf doesn't set it.
344 record.SetTypeAndMisc(PERF_RECORD_BUILD_ID, record.misc());
345 CHECK_LE(p + record.size(), end);
347 result.push_back(std::move(record));
352 std::string RecordFileReader::ReadFeatureString(int feature) {
353 std::vector<char> buf;
354 if (!ReadFeatureSection(feature, &buf)) {
355 return std::string();
357 const char* p = buf.data();
358 const char* end = buf.data() + buf.size();
360 MoveFromBinaryFormat(len, p);
361 CHECK_LE(p + len, end);
365 std::vector<std::unique_ptr<Record>> RecordFileReader::DataSection() {
366 std::vector<std::unique_ptr<Record>> records;
367 ReadDataSection([&](std::unique_ptr<Record> record) {
368 records.push_back(std::move(record));