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"
25 #include <base/logging.h>
28 #include "perf_event.h"
32 using namespace PerfFileFormat;
34 std::unique_ptr<RecordFileWriter> RecordFileWriter::CreateInstance(
35 const std::string& filename, const perf_event_attr& event_attr,
36 const std::vector<std::unique_ptr<EventFd>>& event_fds) {
37 FILE* fp = fopen(filename.c_str(), "web+");
39 PLOG(ERROR) << "failed to open record file '" << filename << "'";
43 auto writer = std::unique_ptr<RecordFileWriter>(new RecordFileWriter(filename, fp));
44 if (!writer->WriteAttrSection(event_attr, event_fds)) {
50 RecordFileWriter::RecordFileWriter(const std::string& filename, FILE* fp)
51 : filename_(filename), record_fp_(fp), data_section_offset_(0), data_section_size_(0) {
54 RecordFileWriter::~RecordFileWriter() {
55 if (record_fp_ != nullptr) {
60 bool RecordFileWriter::WriteAttrSection(const perf_event_attr& event_attr,
61 const std::vector<std::unique_ptr<EventFd>>& event_fds) {
62 // Skip file header part.
63 if (fseek(record_fp_, sizeof(FileHeader), SEEK_SET) == -1) {
68 std::vector<uint64_t> ids;
69 for (auto& event_fd : event_fds) {
70 ids.push_back(event_fd->Id());
72 long id_section_offset = ftell(record_fp_);
73 if (id_section_offset == -1) {
76 if (!Write(ids.data(), ids.size() * sizeof(uint64_t))) {
80 // Write attr section.
82 attr.attr = event_attr;
83 attr.ids.offset = id_section_offset;
84 attr.ids.size = ids.size() * sizeof(uint64_t);
86 long attr_section_offset = ftell(record_fp_);
87 if (attr_section_offset == -1) {
90 if (!Write(&attr, sizeof(attr))) {
94 long data_section_offset = ftell(record_fp_);
95 if (data_section_offset == -1) {
99 attr_section_offset_ = attr_section_offset;
100 attr_section_size_ = sizeof(attr);
101 data_section_offset_ = data_section_offset;
103 // Save event_attr for use when reading records.
104 event_attr_ = event_attr;
108 bool RecordFileWriter::WriteData(const void* buf, size_t len) {
109 if (!Write(buf, len)) {
112 data_section_size_ += len;
116 bool RecordFileWriter::Write(const void* buf, size_t len) {
117 if (fwrite(buf, len, 1, record_fp_) != 1) {
118 PLOG(ERROR) << "failed to write to record file '" << filename_ << "'";
124 bool RecordFileWriter::WriteFileHeader() {
126 memset(&header, 0, sizeof(header));
127 memcpy(header.magic, PERF_MAGIC, sizeof(header.magic));
128 header.header_size = sizeof(header);
129 header.attr_size = sizeof(FileAttr);
130 header.attrs.offset = attr_section_offset_;
131 header.attrs.size = attr_section_size_;
132 header.data.offset = data_section_offset_;
133 header.data.size = data_section_size_;
134 for (auto& feature : features_) {
137 header.features[i] |= (1 << j);
140 if (fseek(record_fp_, 0, SEEK_SET) == -1) {
143 if (!Write(&header, sizeof(header))) {
149 bool RecordFileWriter::Close() {
150 CHECK(record_fp_ != nullptr);
153 // Write file header. We gather enough information to write file header only after
154 // writing data section and feature section.
155 if (!WriteFileHeader()) {
159 if (fclose(record_fp_) != 0) {
160 PLOG(ERROR) << "failed to close record file '" << filename_ << "'";
163 record_fp_ = nullptr;
167 std::unique_ptr<RecordFileReader> RecordFileReader::CreateInstance(const std::string& filename) {
168 int fd = open(filename.c_str(), O_RDONLY | O_CLOEXEC);
170 PLOG(ERROR) << "failed to open record file '" << filename << "'";
173 auto reader = std::unique_ptr<RecordFileReader>(new RecordFileReader(filename, fd));
174 if (!reader->MmapFile()) {
180 RecordFileReader::RecordFileReader(const std::string& filename, int fd)
181 : filename_(filename), record_fd_(fd), mmap_addr_(nullptr), mmap_len_(0) {
184 RecordFileReader::~RecordFileReader() {
185 if (record_fd_ != -1) {
190 bool RecordFileReader::Close() {
192 if (munmap(const_cast<char*>(mmap_addr_), mmap_len_) == -1) {
193 PLOG(ERROR) << "failed to munmap() record file '" << filename_ << "'";
196 if (close(record_fd_) == -1) {
197 PLOG(ERROR) << "failed to close record file '" << filename_ << "'";
204 bool RecordFileReader::MmapFile() {
205 off64_t file_size = lseek64(record_fd_, 0, SEEK_END);
206 if (file_size == -1) {
209 size_t mmap_len = file_size;
210 void* mmap_addr = mmap(nullptr, mmap_len, PROT_READ, MAP_SHARED, record_fd_, 0);
211 if (mmap_addr == MAP_FAILED) {
212 PLOG(ERROR) << "failed to mmap() record file '" << filename_ << "'";
216 mmap_addr_ = reinterpret_cast<const char*>(mmap_addr);
217 mmap_len_ = mmap_len;
221 const FileHeader* RecordFileReader::FileHeader() {
222 return reinterpret_cast<const struct FileHeader*>(mmap_addr_);
225 std::vector<const FileAttr*> RecordFileReader::AttrSection() {
226 std::vector<const FileAttr*> result;
227 const struct FileHeader* header = FileHeader();
228 size_t attr_count = header->attrs.size / header->attr_size;
229 const FileAttr* attr = reinterpret_cast<const FileAttr*>(mmap_addr_ + header->attrs.offset);
230 for (size_t i = 0; i < attr_count; ++i) {
231 result.push_back(attr++);
236 std::vector<uint64_t> RecordFileReader::IdsForAttr(const FileAttr* attr) {
237 std::vector<uint64_t> result;
238 size_t id_count = attr->ids.size / sizeof(uint64_t);
239 const uint64_t* id = reinterpret_cast<const uint64_t*>(mmap_addr_ + attr->ids.offset);
240 for (size_t i = 0; i < id_count; ++i) {
241 result.push_back(*id++);
246 std::vector<std::unique_ptr<const Record>> RecordFileReader::DataSection() {
247 std::vector<std::unique_ptr<const Record>> result;
248 const struct FileHeader* header = FileHeader();
249 auto file_attrs = AttrSection();
250 CHECK(file_attrs.size() > 0);
251 perf_event_attr attr = file_attrs[0]->attr;
253 const char* end = mmap_addr_ + header->data.offset + header->data.size;
254 const char* p = mmap_addr_ + header->data.offset;
256 const perf_event_header* header = reinterpret_cast<const perf_event_header*>(p);
257 if (p + header->size <= end) {
258 result.push_back(std::move(ReadRecordFromBuffer(attr, header)));