OSDN Git Service

Merge "Track rename from base/ to android-base/." am: 5d8fdbb6ff am: 9ff83ae0e4
[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 <android-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::SeekFileEnd(uint64_t* file_end) {
133   if (fseek(record_fp_, 0, SEEK_END) == -1) {
134     PLOG(ERROR) << "fseek() failed";
135     return false;
136   }
137   long offset = ftell(record_fp_);
138   if (offset == -1) {
139     PLOG(ERROR) << "ftell() failed";
140     return false;
141   }
142   *file_end = static_cast<uint64_t>(offset);
143   return true;
144 }
145
146 bool RecordFileWriter::WriteFeatureHeader(size_t feature_count) {
147   feature_count_ = feature_count;
148   current_feature_index_ = 0;
149   uint64_t feature_header_size = feature_count * sizeof(SectionDesc);
150
151   // Reserve enough space in the record file for the feature header.
152   std::vector<unsigned char> zero_data(feature_header_size);
153   if (fseek(record_fp_, data_section_offset_ + data_section_size_, SEEK_SET) == -1) {
154     PLOG(ERROR) << "fseek() failed";
155     return false;
156   }
157   return Write(zero_data.data(), zero_data.size());
158 }
159
160 bool RecordFileWriter::WriteBuildIdFeature(const std::vector<BuildIdRecord>& build_id_records) {
161   uint64_t start_offset;
162   if (!WriteFeatureBegin(&start_offset)) {
163     return false;
164   }
165   for (auto& record : build_id_records) {
166     std::vector<char> data = record.BinaryFormat();
167     if (!Write(data.data(), data.size())) {
168       return false;
169     }
170   }
171   return WriteFeatureEnd(FEAT_BUILD_ID, start_offset);
172 }
173
174 bool RecordFileWriter::WriteFeatureString(int feature, const std::string& s) {
175   uint64_t start_offset;
176   if (!WriteFeatureBegin(&start_offset)) {
177     return false;
178   }
179   uint32_t len = static_cast<uint32_t>(ALIGN(s.size() + 1, 64));
180   if (!Write(&len, sizeof(len))) {
181     return false;
182   }
183   std::vector<char> v(len, '\0');
184   std::copy(s.begin(), s.end(), v.begin());
185   if (!Write(v.data(), v.size())) {
186     return false;
187   }
188   return WriteFeatureEnd(feature, start_offset);
189 }
190
191 bool RecordFileWriter::WriteCmdlineFeature(const std::vector<std::string>& cmdline) {
192   uint64_t start_offset;
193   if (!WriteFeatureBegin(&start_offset)) {
194     return false;
195   }
196   uint32_t arg_count = cmdline.size();
197   if (!Write(&arg_count, sizeof(arg_count))) {
198     return false;
199   }
200   for (auto& arg : cmdline) {
201     uint32_t len = static_cast<uint32_t>(ALIGN(arg.size() + 1, 64));
202     if (!Write(&len, sizeof(len))) {
203       return false;
204     }
205     std::vector<char> array(len, '\0');
206     std::copy(arg.begin(), arg.end(), array.begin());
207     if (!Write(array.data(), array.size())) {
208       return false;
209     }
210   }
211   return WriteFeatureEnd(FEAT_CMDLINE, start_offset);
212 }
213
214 bool RecordFileWriter::WriteBranchStackFeature() {
215   uint64_t start_offset;
216   if (!WriteFeatureBegin(&start_offset)) {
217     return false;
218   }
219   return WriteFeatureEnd(FEAT_BRANCH_STACK, start_offset);
220 }
221
222 bool RecordFileWriter::WriteFeatureBegin(uint64_t* start_offset) {
223   CHECK_LT(current_feature_index_, feature_count_);
224   if (!SeekFileEnd(start_offset)) {
225     return false;
226   }
227   return true;
228 }
229
230 bool RecordFileWriter::WriteFeatureEnd(int feature, uint64_t start_offset) {
231   uint64_t end_offset;
232   if (!SeekFileEnd(&end_offset)) {
233     return false;
234   }
235   SectionDesc desc;
236   desc.offset = start_offset;
237   desc.size = end_offset - start_offset;
238   uint64_t feature_offset = data_section_offset_ + data_section_size_;
239   if (fseek(record_fp_, feature_offset + current_feature_index_ * sizeof(SectionDesc), SEEK_SET) ==
240       -1) {
241     PLOG(ERROR) << "fseek() failed";
242     return false;
243   }
244   if (!Write(&desc, sizeof(SectionDesc))) {
245     return false;
246   }
247   ++current_feature_index_;
248   features_.push_back(feature);
249   return true;
250 }
251
252 bool RecordFileWriter::WriteFileHeader() {
253   FileHeader header;
254   memset(&header, 0, sizeof(header));
255   memcpy(header.magic, PERF_MAGIC, sizeof(header.magic));
256   header.header_size = sizeof(header);
257   header.attr_size = sizeof(FileAttr);
258   header.attrs.offset = attr_section_offset_;
259   header.attrs.size = attr_section_size_;
260   header.data.offset = data_section_offset_;
261   header.data.size = data_section_size_;
262   for (auto& feature : features_) {
263     int i = feature / 8;
264     int j = feature % 8;
265     header.features[i] |= (1 << j);
266   }
267
268   if (fseek(record_fp_, 0, SEEK_SET) == -1) {
269     return false;
270   }
271   if (!Write(&header, sizeof(header))) {
272     return false;
273   }
274   return true;
275 }
276
277 bool RecordFileWriter::Close() {
278   CHECK(record_fp_ != nullptr);
279   bool result = true;
280
281   // Write file header. We gather enough information to write file header only after
282   // writing data section and feature section.
283   if (!WriteFileHeader()) {
284     result = false;
285   }
286
287   if (fclose(record_fp_) != 0) {
288     PLOG(ERROR) << "failed to close record file '" << filename_ << "'";
289     result = false;
290   }
291   record_fp_ = nullptr;
292   return result;
293 }