OSDN Git Service

am e2d1e633: (-s ours) am dfff022d: Merge "ext4_utils: Wrap wipe.h to be C++ compatible."
[android-x86/system-extras.git] / simpleperf / record_file_writer.cpp
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 <sys/mman.h>
22 #include <unistd.h>
23 #include <set>
24 #include <vector>
25
26 #include <base/logging.h>
27
28 #include "perf_event.h"
29 #include "record.h"
30 #include "utils.h"
31
32 using namespace PerfFileFormat;
33
34 std::unique_ptr<RecordFileWriter> RecordFileWriter::CreateInstance(const std::string& filename) {
35   // Remove old perf.data to avoid file ownership problems.
36   if (!RemovePossibleFile(filename)) {
37     return nullptr;
38   }
39   FILE* fp = fopen(filename.c_str(), "web+");
40   if (fp == nullptr) {
41     PLOG(ERROR) << "failed to open record file '" << filename << "'";
42     return nullptr;
43   }
44
45   return std::unique_ptr<RecordFileWriter>(new RecordFileWriter(filename, fp));
46 }
47
48 RecordFileWriter::RecordFileWriter(const std::string& filename, FILE* fp)
49     : filename_(filename),
50       record_fp_(fp),
51       attr_section_offset_(0),
52       attr_section_size_(0),
53       data_section_offset_(0),
54       data_section_size_(0),
55       feature_count_(0),
56       current_feature_index_(0) {
57 }
58
59 RecordFileWriter::~RecordFileWriter() {
60   if (record_fp_ != nullptr) {
61     Close();
62   }
63 }
64
65 bool RecordFileWriter::WriteAttrSection(const std::vector<AttrWithId>& attr_ids) {
66   if (attr_ids.empty()) {
67     return false;
68   }
69
70   // Skip file header part.
71   if (fseek(record_fp_, sizeof(FileHeader), SEEK_SET) == -1) {
72     return false;
73   }
74
75   // Write id section.
76   long id_section_offset = ftell(record_fp_);
77   if (id_section_offset == -1) {
78     return false;
79   }
80   for (auto& attr_id : attr_ids) {
81     if (!Write(attr_id.ids.data(), attr_id.ids.size() * sizeof(uint64_t))) {
82       return false;
83     }
84   }
85
86   // Write attr section.
87   long attr_section_offset = ftell(record_fp_);
88   if (attr_section_offset == -1) {
89     return false;
90   }
91   for (auto& attr_id : attr_ids) {
92     FileAttr file_attr;
93     file_attr.attr = *attr_id.attr;
94     file_attr.ids.offset = id_section_offset;
95     file_attr.ids.size = attr_id.ids.size() * sizeof(uint64_t);
96     id_section_offset += file_attr.ids.size;
97     if (!Write(&file_attr, sizeof(file_attr))) {
98       return false;
99     }
100   }
101
102   long data_section_offset = ftell(record_fp_);
103   if (data_section_offset == -1) {
104     return false;
105   }
106
107   attr_section_offset_ = attr_section_offset;
108   attr_section_size_ = data_section_offset - attr_section_offset;
109   data_section_offset_ = data_section_offset;
110
111   // Save event_attr for use when reading records.
112   event_attr_ = *attr_ids[0].attr;
113   return true;
114 }
115
116 bool RecordFileWriter::WriteData(const void* buf, size_t len) {
117   if (!Write(buf, len)) {
118     return false;
119   }
120   data_section_size_ += len;
121   return true;
122 }
123
124 bool RecordFileWriter::Write(const void* buf, size_t len) {
125   if (fwrite(buf, len, 1, record_fp_) != 1) {
126     PLOG(ERROR) << "failed to write to record file '" << filename_ << "'";
127     return false;
128   }
129   return true;
130 }
131
132 bool RecordFileWriter::ReadDataSection(std::vector<std::unique_ptr<Record>>* records) {
133   if (fflush(record_fp_) != 0) {
134     PLOG(ERROR) << "fflush() failed";
135     return false;
136   }
137   uint64_t file_size;
138   if (!SeekFileEnd(&file_size)) {
139     return false;
140   }
141   size_t mmap_len = static_cast<size_t>(file_size);
142   void* mmap_addr = mmap(nullptr, mmap_len, PROT_READ, MAP_SHARED, fileno(record_fp_), 0);
143   if (mmap_addr == MAP_FAILED) {
144     PLOG(ERROR) << "mmap() failed";
145     return false;
146   }
147   const char* data_section = reinterpret_cast<char*>(mmap_addr) + data_section_offset_;
148   std::vector<std::unique_ptr<Record>> result =
149       ReadRecordsFromBuffer(event_attr_, data_section, data_section_size_);
150   if (munmap(mmap_addr, mmap_len) == -1) {
151     PLOG(ERROR) << "munmap() failed";
152     return false;
153   }
154   *records = std::move(result);
155   return true;
156 }
157
158 bool RecordFileWriter::SeekFileEnd(uint64_t* file_end) {
159   if (fseek(record_fp_, 0, SEEK_END) == -1) {
160     PLOG(ERROR) << "fseek() failed";
161     return false;
162   }
163   long offset = ftell(record_fp_);
164   if (offset == -1) {
165     PLOG(ERROR) << "ftell() failed";
166     return false;
167   }
168   *file_end = static_cast<uint64_t>(offset);
169   return true;
170 }
171
172 bool RecordFileWriter::WriteFeatureHeader(size_t feature_count) {
173   feature_count_ = feature_count;
174   current_feature_index_ = 0;
175   uint64_t feature_header_size = feature_count * sizeof(SectionDesc);
176
177   // Reserve enough space in the record file for the feature header.
178   std::vector<unsigned char> zero_data(feature_header_size);
179   if (fseek(record_fp_, data_section_offset_ + data_section_size_, SEEK_SET) == -1) {
180     PLOG(ERROR) << "fseek() failed";
181     return false;
182   }
183   return Write(zero_data.data(), zero_data.size());
184 }
185
186 bool RecordFileWriter::WriteBuildIdFeature(const std::vector<BuildIdRecord>& build_id_records) {
187   uint64_t start_offset;
188   if (!WriteFeatureBegin(&start_offset)) {
189     return false;
190   }
191   for (auto& record : build_id_records) {
192     std::vector<char> data = record.BinaryFormat();
193     if (!Write(data.data(), data.size())) {
194       return false;
195     }
196   }
197   return WriteFeatureEnd(FEAT_BUILD_ID, start_offset);
198 }
199
200 bool RecordFileWriter::WriteFeatureString(int feature, const std::string& s) {
201   uint64_t start_offset;
202   if (!WriteFeatureBegin(&start_offset)) {
203     return false;
204   }
205   uint32_t len = static_cast<uint32_t>(ALIGN(s.size() + 1, 64));
206   if (!Write(&len, sizeof(len))) {
207     return false;
208   }
209   std::vector<char> v(len, '\0');
210   std::copy(s.begin(), s.end(), v.begin());
211   if (!Write(v.data(), v.size())) {
212     return false;
213   }
214   return WriteFeatureEnd(feature, start_offset);
215 }
216
217 bool RecordFileWriter::WriteCmdlineFeature(const std::vector<std::string>& cmdline) {
218   uint64_t start_offset;
219   if (!WriteFeatureBegin(&start_offset)) {
220     return false;
221   }
222   uint32_t arg_count = cmdline.size();
223   if (!Write(&arg_count, sizeof(arg_count))) {
224     return false;
225   }
226   for (auto& arg : cmdline) {
227     uint32_t len = static_cast<uint32_t>(ALIGN(arg.size() + 1, 64));
228     if (!Write(&len, sizeof(len))) {
229       return false;
230     }
231     std::vector<char> array(len, '\0');
232     std::copy(arg.begin(), arg.end(), array.begin());
233     if (!Write(array.data(), array.size())) {
234       return false;
235     }
236   }
237   return WriteFeatureEnd(FEAT_CMDLINE, start_offset);
238 }
239
240 bool RecordFileWriter::WriteBranchStackFeature() {
241   uint64_t start_offset;
242   if (!WriteFeatureBegin(&start_offset)) {
243     return false;
244   }
245   return WriteFeatureEnd(FEAT_BRANCH_STACK, start_offset);
246 }
247
248 bool RecordFileWriter::WriteFeatureBegin(uint64_t* start_offset) {
249   CHECK_LT(current_feature_index_, feature_count_);
250   if (!SeekFileEnd(start_offset)) {
251     return false;
252   }
253   return true;
254 }
255
256 bool RecordFileWriter::WriteFeatureEnd(int feature, uint64_t start_offset) {
257   uint64_t end_offset;
258   if (!SeekFileEnd(&end_offset)) {
259     return false;
260   }
261   SectionDesc desc;
262   desc.offset = start_offset;
263   desc.size = end_offset - start_offset;
264   uint64_t feature_offset = data_section_offset_ + data_section_size_;
265   if (fseek(record_fp_, feature_offset + current_feature_index_ * sizeof(SectionDesc), SEEK_SET) ==
266       -1) {
267     PLOG(ERROR) << "fseek() failed";
268     return false;
269   }
270   if (!Write(&desc, sizeof(SectionDesc))) {
271     return false;
272   }
273   ++current_feature_index_;
274   features_.push_back(feature);
275   return true;
276 }
277
278 bool RecordFileWriter::WriteFileHeader() {
279   FileHeader header;
280   memset(&header, 0, sizeof(header));
281   memcpy(header.magic, PERF_MAGIC, sizeof(header.magic));
282   header.header_size = sizeof(header);
283   header.attr_size = sizeof(FileAttr);
284   header.attrs.offset = attr_section_offset_;
285   header.attrs.size = attr_section_size_;
286   header.data.offset = data_section_offset_;
287   header.data.size = data_section_size_;
288   for (auto& feature : features_) {
289     int i = feature / 8;
290     int j = feature % 8;
291     header.features[i] |= (1 << j);
292   }
293
294   if (fseek(record_fp_, 0, SEEK_SET) == -1) {
295     return false;
296   }
297   if (!Write(&header, sizeof(header))) {
298     return false;
299   }
300   return true;
301 }
302
303 bool RecordFileWriter::Close() {
304   CHECK(record_fp_ != nullptr);
305   bool result = true;
306
307   // Write file header. We gather enough information to write file header only after
308   // writing data section and feature section.
309   if (!WriteFileHeader()) {
310     result = false;
311   }
312
313   if (fclose(record_fp_) != 0) {
314     PLOG(ERROR) << "failed to close record file '" << filename_ << "'";
315     result = false;
316   }
317   record_fp_ = nullptr;
318   return result;
319 }