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