1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker * Copyright (C) 2020 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker *
4*288bf522SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker *
8*288bf522SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker *
10*288bf522SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker */
16*288bf522SAndroid Build Coastguard Worker
17*288bf522SAndroid Build Coastguard Worker #include <stdio.h>
18*288bf522SAndroid Build Coastguard Worker
19*288bf522SAndroid Build Coastguard Worker #include <memory>
20*288bf522SAndroid Build Coastguard Worker #include <regex>
21*288bf522SAndroid Build Coastguard Worker #include <string>
22*288bf522SAndroid Build Coastguard Worker
23*288bf522SAndroid Build Coastguard Worker #include <android-base/macros.h>
24*288bf522SAndroid Build Coastguard Worker #include <android-base/strings.h>
25*288bf522SAndroid Build Coastguard Worker
26*288bf522SAndroid Build Coastguard Worker #include "command.h"
27*288bf522SAndroid Build Coastguard Worker #include "event_attr.h"
28*288bf522SAndroid Build Coastguard Worker #include "record_file.h"
29*288bf522SAndroid Build Coastguard Worker #include "thread_tree.h"
30*288bf522SAndroid Build Coastguard Worker #include "utils.h"
31*288bf522SAndroid Build Coastguard Worker
32*288bf522SAndroid Build Coastguard Worker namespace simpleperf {
33*288bf522SAndroid Build Coastguard Worker namespace {
34*288bf522SAndroid Build Coastguard Worker
35*288bf522SAndroid Build Coastguard Worker class MergedFileFeature {
36*288bf522SAndroid Build Coastguard Worker public:
MergedFileFeature(FileFeature & file)37*288bf522SAndroid Build Coastguard Worker MergedFileFeature(FileFeature& file)
38*288bf522SAndroid Build Coastguard Worker : path_(file.path),
39*288bf522SAndroid Build Coastguard Worker type_(file.type),
40*288bf522SAndroid Build Coastguard Worker min_vaddr_(file.min_vaddr),
41*288bf522SAndroid Build Coastguard Worker file_offset_of_min_vaddr_(file.file_offset_of_min_vaddr),
42*288bf522SAndroid Build Coastguard Worker dex_file_offsets_(std::move(file.dex_file_offsets)) {
43*288bf522SAndroid Build Coastguard Worker for (auto& symbol : file.symbols) {
44*288bf522SAndroid Build Coastguard Worker symbol_map_.emplace(symbol.addr, std::move(symbol));
45*288bf522SAndroid Build Coastguard Worker }
46*288bf522SAndroid Build Coastguard Worker }
47*288bf522SAndroid Build Coastguard Worker
Merge(FileFeature & file)48*288bf522SAndroid Build Coastguard Worker bool Merge(FileFeature& file) {
49*288bf522SAndroid Build Coastguard Worker if (file.type != type_ || file.min_vaddr != min_vaddr_ ||
50*288bf522SAndroid Build Coastguard Worker file.file_offset_of_min_vaddr != file_offset_of_min_vaddr_ ||
51*288bf522SAndroid Build Coastguard Worker file.dex_file_offsets != dex_file_offsets_) {
52*288bf522SAndroid Build Coastguard Worker return false;
53*288bf522SAndroid Build Coastguard Worker }
54*288bf522SAndroid Build Coastguard Worker for (auto& symbol : file.symbols) {
55*288bf522SAndroid Build Coastguard Worker auto it = symbol_map_.lower_bound(symbol.addr);
56*288bf522SAndroid Build Coastguard Worker if (it != symbol_map_.end()) {
57*288bf522SAndroid Build Coastguard Worker const auto& found = it->second;
58*288bf522SAndroid Build Coastguard Worker if (found.addr == symbol.addr && found.len == symbol.len &&
59*288bf522SAndroid Build Coastguard Worker strcmp(found.Name(), symbol.Name()) == 0) {
60*288bf522SAndroid Build Coastguard Worker // The symbol already exists in symbol_map.
61*288bf522SAndroid Build Coastguard Worker continue;
62*288bf522SAndroid Build Coastguard Worker }
63*288bf522SAndroid Build Coastguard Worker if (symbol.addr + symbol.len > found.addr) {
64*288bf522SAndroid Build Coastguard Worker // an address conflict with the next symbol
65*288bf522SAndroid Build Coastguard Worker return false;
66*288bf522SAndroid Build Coastguard Worker }
67*288bf522SAndroid Build Coastguard Worker }
68*288bf522SAndroid Build Coastguard Worker if (it != symbol_map_.begin()) {
69*288bf522SAndroid Build Coastguard Worker --it;
70*288bf522SAndroid Build Coastguard Worker if (it->second.addr + it->second.len > symbol.addr) {
71*288bf522SAndroid Build Coastguard Worker // an address conflict with the previous symbol
72*288bf522SAndroid Build Coastguard Worker return false;
73*288bf522SAndroid Build Coastguard Worker }
74*288bf522SAndroid Build Coastguard Worker }
75*288bf522SAndroid Build Coastguard Worker symbol_map_.emplace(symbol.addr, std::move(symbol));
76*288bf522SAndroid Build Coastguard Worker }
77*288bf522SAndroid Build Coastguard Worker return true;
78*288bf522SAndroid Build Coastguard Worker }
79*288bf522SAndroid Build Coastguard Worker
ToFileFeature(FileFeature * file) const80*288bf522SAndroid Build Coastguard Worker void ToFileFeature(FileFeature* file) const {
81*288bf522SAndroid Build Coastguard Worker file->path = path_;
82*288bf522SAndroid Build Coastguard Worker file->type = type_;
83*288bf522SAndroid Build Coastguard Worker file->min_vaddr = min_vaddr_;
84*288bf522SAndroid Build Coastguard Worker file->file_offset_of_min_vaddr = file_offset_of_min_vaddr_;
85*288bf522SAndroid Build Coastguard Worker file->symbol_ptrs.clear();
86*288bf522SAndroid Build Coastguard Worker for (const auto& [_, symbol] : symbol_map_) {
87*288bf522SAndroid Build Coastguard Worker file->symbol_ptrs.emplace_back(&symbol);
88*288bf522SAndroid Build Coastguard Worker }
89*288bf522SAndroid Build Coastguard Worker file->dex_file_offsets = dex_file_offsets_;
90*288bf522SAndroid Build Coastguard Worker }
91*288bf522SAndroid Build Coastguard Worker
92*288bf522SAndroid Build Coastguard Worker private:
93*288bf522SAndroid Build Coastguard Worker std::string path_;
94*288bf522SAndroid Build Coastguard Worker DsoType type_;
95*288bf522SAndroid Build Coastguard Worker uint64_t min_vaddr_;
96*288bf522SAndroid Build Coastguard Worker uint64_t file_offset_of_min_vaddr_;
97*288bf522SAndroid Build Coastguard Worker std::map<uint64_t, Symbol> symbol_map_;
98*288bf522SAndroid Build Coastguard Worker std::vector<uint64_t> dex_file_offsets_;
99*288bf522SAndroid Build Coastguard Worker
100*288bf522SAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(MergedFileFeature);
101*288bf522SAndroid Build Coastguard Worker };
102*288bf522SAndroid Build Coastguard Worker
103*288bf522SAndroid Build Coastguard Worker class MergeCommand : public Command {
104*288bf522SAndroid Build Coastguard Worker public:
MergeCommand()105*288bf522SAndroid Build Coastguard Worker MergeCommand()
106*288bf522SAndroid Build Coastguard Worker : Command("merge", "merge multiple perf.data into one",
107*288bf522SAndroid Build Coastguard Worker // clang-format off
108*288bf522SAndroid Build Coastguard Worker "Usage: simpleperf merge [options]\n"
109*288bf522SAndroid Build Coastguard Worker " Merge multiple perf.data into one. The input files should be recorded on the same\n"
110*288bf522SAndroid Build Coastguard Worker " device using the same event types.\n"
111*288bf522SAndroid Build Coastguard Worker "-i <file1>,<file2>,... Input recording files separated by comma\n"
112*288bf522SAndroid Build Coastguard Worker "-o <file> output recording file\n"
113*288bf522SAndroid Build Coastguard Worker "\n"
114*288bf522SAndroid Build Coastguard Worker "Examples:\n"
115*288bf522SAndroid Build Coastguard Worker "$ simpleperf merge -i perf1.data,perf2.data -o perf.data\n"
116*288bf522SAndroid Build Coastguard Worker // clang-format on
117*288bf522SAndroid Build Coastguard Worker ) {}
118*288bf522SAndroid Build Coastguard Worker
Run(const std::vector<std::string> & args)119*288bf522SAndroid Build Coastguard Worker bool Run(const std::vector<std::string>& args) override {
120*288bf522SAndroid Build Coastguard Worker // 1. Parse options.
121*288bf522SAndroid Build Coastguard Worker if (!ParseOptions(args)) {
122*288bf522SAndroid Build Coastguard Worker return false;
123*288bf522SAndroid Build Coastguard Worker }
124*288bf522SAndroid Build Coastguard Worker
125*288bf522SAndroid Build Coastguard Worker // 2. Open input files and check if they are mergeable.
126*288bf522SAndroid Build Coastguard Worker for (const auto& file : input_files_) {
127*288bf522SAndroid Build Coastguard Worker readers_.emplace_back(RecordFileReader::CreateInstance(file));
128*288bf522SAndroid Build Coastguard Worker if (!readers_.back()) {
129*288bf522SAndroid Build Coastguard Worker return false;
130*288bf522SAndroid Build Coastguard Worker }
131*288bf522SAndroid Build Coastguard Worker }
132*288bf522SAndroid Build Coastguard Worker if (!IsMergeable()) {
133*288bf522SAndroid Build Coastguard Worker return false;
134*288bf522SAndroid Build Coastguard Worker }
135*288bf522SAndroid Build Coastguard Worker
136*288bf522SAndroid Build Coastguard Worker // 3. Merge files.
137*288bf522SAndroid Build Coastguard Worker writer_ = RecordFileWriter::CreateInstance(output_file_);
138*288bf522SAndroid Build Coastguard Worker if (!writer_) {
139*288bf522SAndroid Build Coastguard Worker return false;
140*288bf522SAndroid Build Coastguard Worker }
141*288bf522SAndroid Build Coastguard Worker if (!MergeAttrSection() || !MergeDataSection() || !MergeFeatureSection()) {
142*288bf522SAndroid Build Coastguard Worker return false;
143*288bf522SAndroid Build Coastguard Worker }
144*288bf522SAndroid Build Coastguard Worker return writer_->Close();
145*288bf522SAndroid Build Coastguard Worker }
146*288bf522SAndroid Build Coastguard Worker
147*288bf522SAndroid Build Coastguard Worker private:
ParseOptions(const std::vector<std::string> & args)148*288bf522SAndroid Build Coastguard Worker bool ParseOptions(const std::vector<std::string>& args) {
149*288bf522SAndroid Build Coastguard Worker const OptionFormatMap option_formats = {
150*288bf522SAndroid Build Coastguard Worker {"-i", {OptionValueType::STRING, OptionType::MULTIPLE}},
151*288bf522SAndroid Build Coastguard Worker {"-o", {OptionValueType::STRING, OptionType::SINGLE}},
152*288bf522SAndroid Build Coastguard Worker };
153*288bf522SAndroid Build Coastguard Worker OptionValueMap options;
154*288bf522SAndroid Build Coastguard Worker std::vector<std::pair<OptionName, OptionValue>> ordered_options;
155*288bf522SAndroid Build Coastguard Worker if (!PreprocessOptions(args, option_formats, &options, &ordered_options, nullptr)) {
156*288bf522SAndroid Build Coastguard Worker return false;
157*288bf522SAndroid Build Coastguard Worker }
158*288bf522SAndroid Build Coastguard Worker for (const OptionValue& value : options.PullValues("-i")) {
159*288bf522SAndroid Build Coastguard Worker auto files = android::base::Split(value.str_value, ",");
160*288bf522SAndroid Build Coastguard Worker input_files_.insert(input_files_.end(), files.begin(), files.end());
161*288bf522SAndroid Build Coastguard Worker }
162*288bf522SAndroid Build Coastguard Worker options.PullStringValue("-o", &output_file_);
163*288bf522SAndroid Build Coastguard Worker
164*288bf522SAndroid Build Coastguard Worker CHECK(options.values.empty());
165*288bf522SAndroid Build Coastguard Worker
166*288bf522SAndroid Build Coastguard Worker if (input_files_.empty()) {
167*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "missing input files";
168*288bf522SAndroid Build Coastguard Worker return false;
169*288bf522SAndroid Build Coastguard Worker }
170*288bf522SAndroid Build Coastguard Worker if (output_file_.empty()) {
171*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "missing output file";
172*288bf522SAndroid Build Coastguard Worker return false;
173*288bf522SAndroid Build Coastguard Worker }
174*288bf522SAndroid Build Coastguard Worker return true;
175*288bf522SAndroid Build Coastguard Worker }
176*288bf522SAndroid Build Coastguard Worker
IsMergeable()177*288bf522SAndroid Build Coastguard Worker bool IsMergeable() { return CheckFeatureSection() && CheckAttrSection(); }
178*288bf522SAndroid Build Coastguard Worker
179*288bf522SAndroid Build Coastguard Worker // Check feature sections to know if the recording environments are the same.
CheckFeatureSection()180*288bf522SAndroid Build Coastguard Worker bool CheckFeatureSection() {
181*288bf522SAndroid Build Coastguard Worker auto get_arch = [](std::unique_ptr<RecordFileReader>& reader) {
182*288bf522SAndroid Build Coastguard Worker return reader->ReadFeatureString(PerfFileFormat::FEAT_ARCH);
183*288bf522SAndroid Build Coastguard Worker };
184*288bf522SAndroid Build Coastguard Worker auto get_kernel_version = [](std::unique_ptr<RecordFileReader>& reader) {
185*288bf522SAndroid Build Coastguard Worker return reader->ReadFeatureString(PerfFileFormat::FEAT_OSRELEASE);
186*288bf522SAndroid Build Coastguard Worker };
187*288bf522SAndroid Build Coastguard Worker auto get_meta_info = [](std::unique_ptr<RecordFileReader>& reader, const char* key) {
188*288bf522SAndroid Build Coastguard Worker auto it = reader->GetMetaInfoFeature().find(key);
189*288bf522SAndroid Build Coastguard Worker return it == reader->GetMetaInfoFeature().end() ? "" : it->second;
190*288bf522SAndroid Build Coastguard Worker };
191*288bf522SAndroid Build Coastguard Worker auto get_simpleperf_version = [&](std::unique_ptr<RecordFileReader>& reader) {
192*288bf522SAndroid Build Coastguard Worker return get_meta_info(reader, "simpleperf_version");
193*288bf522SAndroid Build Coastguard Worker };
194*288bf522SAndroid Build Coastguard Worker auto get_trace_offcpu = [&](std::unique_ptr<RecordFileReader>& reader) {
195*288bf522SAndroid Build Coastguard Worker return get_meta_info(reader, "trace_offcpu");
196*288bf522SAndroid Build Coastguard Worker };
197*288bf522SAndroid Build Coastguard Worker auto get_event_types = [&](std::unique_ptr<RecordFileReader>& reader) {
198*288bf522SAndroid Build Coastguard Worker std::string s = get_meta_info(reader, "event_type_info");
199*288bf522SAndroid Build Coastguard Worker std::vector<std::string> v = android::base::Split(s, "\n");
200*288bf522SAndroid Build Coastguard Worker std::sort(v.begin(), v.end());
201*288bf522SAndroid Build Coastguard Worker return android::base::Join(v, ";");
202*288bf522SAndroid Build Coastguard Worker };
203*288bf522SAndroid Build Coastguard Worker auto get_android_device = [&](std::unique_ptr<RecordFileReader>& reader) {
204*288bf522SAndroid Build Coastguard Worker return get_meta_info(reader, "product_props");
205*288bf522SAndroid Build Coastguard Worker };
206*288bf522SAndroid Build Coastguard Worker auto get_android_version = [&](std::unique_ptr<RecordFileReader>& reader) {
207*288bf522SAndroid Build Coastguard Worker return get_meta_info(reader, "android_version");
208*288bf522SAndroid Build Coastguard Worker };
209*288bf522SAndroid Build Coastguard Worker auto get_app_package_name = [&](std::unique_ptr<RecordFileReader>& reader) {
210*288bf522SAndroid Build Coastguard Worker return get_meta_info(reader, "app_package_name");
211*288bf522SAndroid Build Coastguard Worker };
212*288bf522SAndroid Build Coastguard Worker auto get_clockid = [&](std::unique_ptr<RecordFileReader>& reader) {
213*288bf522SAndroid Build Coastguard Worker return get_meta_info(reader, "clockid");
214*288bf522SAndroid Build Coastguard Worker };
215*288bf522SAndroid Build Coastguard Worker auto get_used_features = [](std::unique_ptr<RecordFileReader>& reader) {
216*288bf522SAndroid Build Coastguard Worker std::string s;
217*288bf522SAndroid Build Coastguard Worker for (const auto& [key, _] : reader->FeatureSectionDescriptors()) {
218*288bf522SAndroid Build Coastguard Worker s += std::to_string(key) + ",";
219*288bf522SAndroid Build Coastguard Worker }
220*288bf522SAndroid Build Coastguard Worker return s;
221*288bf522SAndroid Build Coastguard Worker };
222*288bf522SAndroid Build Coastguard Worker
223*288bf522SAndroid Build Coastguard Worker using value_func_t = std::function<std::string(std::unique_ptr<RecordFileReader>&)>;
224*288bf522SAndroid Build Coastguard Worker std::vector<std::pair<std::string, value_func_t>> check_entries = {
225*288bf522SAndroid Build Coastguard Worker std::make_pair("arch", get_arch),
226*288bf522SAndroid Build Coastguard Worker std::make_pair("kernel_version", get_kernel_version),
227*288bf522SAndroid Build Coastguard Worker std::make_pair("simpleperf_version", get_simpleperf_version),
228*288bf522SAndroid Build Coastguard Worker std::make_pair("trace_offcpu", get_trace_offcpu),
229*288bf522SAndroid Build Coastguard Worker std::make_pair("event_types", get_event_types),
230*288bf522SAndroid Build Coastguard Worker std::make_pair("android_device", get_android_device),
231*288bf522SAndroid Build Coastguard Worker std::make_pair("android_version", get_android_version),
232*288bf522SAndroid Build Coastguard Worker std::make_pair("app_package_name", get_app_package_name),
233*288bf522SAndroid Build Coastguard Worker std::make_pair("clockid", get_clockid),
234*288bf522SAndroid Build Coastguard Worker std::make_pair("used_features", get_used_features),
235*288bf522SAndroid Build Coastguard Worker };
236*288bf522SAndroid Build Coastguard Worker
237*288bf522SAndroid Build Coastguard Worker for (const auto& [name, get_value] : check_entries) {
238*288bf522SAndroid Build Coastguard Worker std::string value0 = get_value(readers_[0]);
239*288bf522SAndroid Build Coastguard Worker for (size_t i = 1; i < readers_.size(); i++) {
240*288bf522SAndroid Build Coastguard Worker std::string value = get_value(readers_[i]);
241*288bf522SAndroid Build Coastguard Worker if (value != value0) {
242*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << input_files_[0] << " and " << input_files_[i] << " are not mergeable for "
243*288bf522SAndroid Build Coastguard Worker << name << " difference: " << value0 << " vs " << value;
244*288bf522SAndroid Build Coastguard Worker return false;
245*288bf522SAndroid Build Coastguard Worker }
246*288bf522SAndroid Build Coastguard Worker }
247*288bf522SAndroid Build Coastguard Worker }
248*288bf522SAndroid Build Coastguard Worker
249*288bf522SAndroid Build Coastguard Worker if (readers_[0]->HasFeature(PerfFileFormat::FEAT_AUXTRACE)) {
250*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << "merging of recording files with auxtrace feature isn't supported";
251*288bf522SAndroid Build Coastguard Worker return false;
252*288bf522SAndroid Build Coastguard Worker }
253*288bf522SAndroid Build Coastguard Worker return true;
254*288bf522SAndroid Build Coastguard Worker }
255*288bf522SAndroid Build Coastguard Worker
256*288bf522SAndroid Build Coastguard Worker // Check attr sections to know if recorded event types are the same.
CheckAttrSection()257*288bf522SAndroid Build Coastguard Worker bool CheckAttrSection() {
258*288bf522SAndroid Build Coastguard Worker const EventAttrIds& attrs0 = readers_[0]->AttrSection();
259*288bf522SAndroid Build Coastguard Worker for (size_t i = 1; i < readers_.size(); i++) {
260*288bf522SAndroid Build Coastguard Worker const EventAttrIds& attrs = readers_[i]->AttrSection();
261*288bf522SAndroid Build Coastguard Worker if (attrs.size() != attrs0.size()) {
262*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << input_files_[0] << " and " << input_files_[i]
263*288bf522SAndroid Build Coastguard Worker << " are not mergeable for recording different event types";
264*288bf522SAndroid Build Coastguard Worker return false;
265*288bf522SAndroid Build Coastguard Worker }
266*288bf522SAndroid Build Coastguard Worker for (size_t attr_id = 0; attr_id < attrs.size(); attr_id++) {
267*288bf522SAndroid Build Coastguard Worker if (attrs[attr_id].attr != attrs0[attr_id].attr) {
268*288bf522SAndroid Build Coastguard Worker LOG(ERROR) << input_files_[0] << " and " << input_files_[i]
269*288bf522SAndroid Build Coastguard Worker << " are not mergeable for recording different event types";
270*288bf522SAndroid Build Coastguard Worker return false;
271*288bf522SAndroid Build Coastguard Worker }
272*288bf522SAndroid Build Coastguard Worker }
273*288bf522SAndroid Build Coastguard Worker }
274*288bf522SAndroid Build Coastguard Worker return true;
275*288bf522SAndroid Build Coastguard Worker }
276*288bf522SAndroid Build Coastguard Worker
MergeAttrSection()277*288bf522SAndroid Build Coastguard Worker bool MergeAttrSection() { return writer_->WriteAttrSection(readers_[0]->AttrSection()); }
278*288bf522SAndroid Build Coastguard Worker
MergeDataSection()279*288bf522SAndroid Build Coastguard Worker bool MergeDataSection() {
280*288bf522SAndroid Build Coastguard Worker for (size_t i = 0; i < readers_.size(); i++) {
281*288bf522SAndroid Build Coastguard Worker if (i != 0) {
282*288bf522SAndroid Build Coastguard Worker if (!WriteGapInDataSection(i - 1, i)) {
283*288bf522SAndroid Build Coastguard Worker return false;
284*288bf522SAndroid Build Coastguard Worker }
285*288bf522SAndroid Build Coastguard Worker }
286*288bf522SAndroid Build Coastguard Worker auto callback = [this](std::unique_ptr<Record> record) {
287*288bf522SAndroid Build Coastguard Worker return ProcessRecord(record.get());
288*288bf522SAndroid Build Coastguard Worker };
289*288bf522SAndroid Build Coastguard Worker if (!readers_[i]->ReadDataSection(callback)) {
290*288bf522SAndroid Build Coastguard Worker return false;
291*288bf522SAndroid Build Coastguard Worker }
292*288bf522SAndroid Build Coastguard Worker }
293*288bf522SAndroid Build Coastguard Worker return true;
294*288bf522SAndroid Build Coastguard Worker }
295*288bf522SAndroid Build Coastguard Worker
ProcessRecord(Record * record)296*288bf522SAndroid Build Coastguard Worker bool ProcessRecord(Record* record) { return writer_->WriteRecord(*record); }
297*288bf522SAndroid Build Coastguard Worker
WriteGapInDataSection(size_t prev_reader_id,size_t next_reader_id)298*288bf522SAndroid Build Coastguard Worker bool WriteGapInDataSection(size_t prev_reader_id, size_t next_reader_id) {
299*288bf522SAndroid Build Coastguard Worker // MergeAttrSection() only maps event_ids in readers_[0] to event attrs. So we need to
300*288bf522SAndroid Build Coastguard Worker // map event_ids in readers_[next_read_id] to event attrs. The map info is put into an
301*288bf522SAndroid Build Coastguard Worker // EventIdRecord.
302*288bf522SAndroid Build Coastguard Worker const std::unordered_map<uint64_t, size_t>& cur_map = readers_[prev_reader_id]->EventIdMap();
303*288bf522SAndroid Build Coastguard Worker const EventAttrIds& attrs = readers_[next_reader_id]->AttrSection();
304*288bf522SAndroid Build Coastguard Worker std::vector<uint64_t> event_id_data;
305*288bf522SAndroid Build Coastguard Worker for (size_t attr_id = 0; attr_id < attrs.size(); attr_id++) {
306*288bf522SAndroid Build Coastguard Worker for (size_t event_id : attrs[attr_id].ids) {
307*288bf522SAndroid Build Coastguard Worker if (auto it = cur_map.find(event_id); it == cur_map.end() || it->second != attr_id) {
308*288bf522SAndroid Build Coastguard Worker event_id_data.push_back(attr_id);
309*288bf522SAndroid Build Coastguard Worker event_id_data.push_back(event_id);
310*288bf522SAndroid Build Coastguard Worker }
311*288bf522SAndroid Build Coastguard Worker }
312*288bf522SAndroid Build Coastguard Worker }
313*288bf522SAndroid Build Coastguard Worker if (!event_id_data.empty()) {
314*288bf522SAndroid Build Coastguard Worker EventIdRecord record(event_id_data);
315*288bf522SAndroid Build Coastguard Worker if (!ProcessRecord(&record)) {
316*288bf522SAndroid Build Coastguard Worker return false;
317*288bf522SAndroid Build Coastguard Worker }
318*288bf522SAndroid Build Coastguard Worker }
319*288bf522SAndroid Build Coastguard Worker return true;
320*288bf522SAndroid Build Coastguard Worker }
321*288bf522SAndroid Build Coastguard Worker
MergeFeatureSection()322*288bf522SAndroid Build Coastguard Worker bool MergeFeatureSection() {
323*288bf522SAndroid Build Coastguard Worker std::vector<int> features;
324*288bf522SAndroid Build Coastguard Worker for (const auto& [key, _] : readers_[0]->FeatureSectionDescriptors()) {
325*288bf522SAndroid Build Coastguard Worker features.push_back(key);
326*288bf522SAndroid Build Coastguard Worker }
327*288bf522SAndroid Build Coastguard Worker if (!writer_->BeginWriteFeatures(features.size())) {
328*288bf522SAndroid Build Coastguard Worker return false;
329*288bf522SAndroid Build Coastguard Worker }
330*288bf522SAndroid Build Coastguard Worker for (int feature : features) {
331*288bf522SAndroid Build Coastguard Worker if (feature == PerfFileFormat::FEAT_OSRELEASE || feature == PerfFileFormat::FEAT_ARCH ||
332*288bf522SAndroid Build Coastguard Worker feature == PerfFileFormat::FEAT_BRANCH_STACK ||
333*288bf522SAndroid Build Coastguard Worker feature == PerfFileFormat::FEAT_META_INFO || feature == PerfFileFormat::FEAT_CMDLINE) {
334*288bf522SAndroid Build Coastguard Worker std::vector<char> data;
335*288bf522SAndroid Build Coastguard Worker if (!readers_[0]->ReadFeatureSection(feature, &data) ||
336*288bf522SAndroid Build Coastguard Worker !writer_->WriteFeature(feature, data.data(), data.size())) {
337*288bf522SAndroid Build Coastguard Worker return false;
338*288bf522SAndroid Build Coastguard Worker }
339*288bf522SAndroid Build Coastguard Worker } else if (feature == PerfFileFormat::FEAT_BUILD_ID) {
340*288bf522SAndroid Build Coastguard Worker WriteBuildIdFeature();
341*288bf522SAndroid Build Coastguard Worker } else if (feature == PerfFileFormat::FEAT_FILE || feature == PerfFileFormat::FEAT_FILE2) {
342*288bf522SAndroid Build Coastguard Worker WriteFileFeature();
343*288bf522SAndroid Build Coastguard Worker } else {
344*288bf522SAndroid Build Coastguard Worker LOG(WARNING) << "Drop feature " << feature << ", which isn't supported in the merge cmd.";
345*288bf522SAndroid Build Coastguard Worker }
346*288bf522SAndroid Build Coastguard Worker }
347*288bf522SAndroid Build Coastguard Worker return writer_->EndWriteFeatures();
348*288bf522SAndroid Build Coastguard Worker }
349*288bf522SAndroid Build Coastguard Worker
WriteBuildIdFeature()350*288bf522SAndroid Build Coastguard Worker bool WriteBuildIdFeature() {
351*288bf522SAndroid Build Coastguard Worker std::map<std::string, BuildIdRecord> build_ids;
352*288bf522SAndroid Build Coastguard Worker std::unordered_set<std::string> files_to_drop;
353*288bf522SAndroid Build Coastguard Worker for (auto& reader : readers_) {
354*288bf522SAndroid Build Coastguard Worker for (auto& record : reader->ReadBuildIdFeature()) {
355*288bf522SAndroid Build Coastguard Worker auto it = build_ids.find(record.filename);
356*288bf522SAndroid Build Coastguard Worker if (it == build_ids.end()) {
357*288bf522SAndroid Build Coastguard Worker build_ids.emplace(record.filename, std::move(record));
358*288bf522SAndroid Build Coastguard Worker } else if (it->second.build_id != record.build_id) {
359*288bf522SAndroid Build Coastguard Worker if (files_to_drop.count(record.filename) == 0) {
360*288bf522SAndroid Build Coastguard Worker files_to_drop.emplace(record.filename);
361*288bf522SAndroid Build Coastguard Worker LOG(WARNING)
362*288bf522SAndroid Build Coastguard Worker << record.filename
363*288bf522SAndroid Build Coastguard Worker << " has different build ids in different record files. So drop its build ids.";
364*288bf522SAndroid Build Coastguard Worker }
365*288bf522SAndroid Build Coastguard Worker }
366*288bf522SAndroid Build Coastguard Worker }
367*288bf522SAndroid Build Coastguard Worker }
368*288bf522SAndroid Build Coastguard Worker std::vector<BuildIdRecord> records;
369*288bf522SAndroid Build Coastguard Worker for (auto& [filename, record] : build_ids) {
370*288bf522SAndroid Build Coastguard Worker if (files_to_drop.count(filename) == 0) {
371*288bf522SAndroid Build Coastguard Worker records.emplace_back(std::move(record));
372*288bf522SAndroid Build Coastguard Worker }
373*288bf522SAndroid Build Coastguard Worker }
374*288bf522SAndroid Build Coastguard Worker return writer_->WriteBuildIdFeature(records);
375*288bf522SAndroid Build Coastguard Worker }
376*288bf522SAndroid Build Coastguard Worker
WriteFileFeature()377*288bf522SAndroid Build Coastguard Worker bool WriteFileFeature() {
378*288bf522SAndroid Build Coastguard Worker std::map<std::string, MergedFileFeature> file_map;
379*288bf522SAndroid Build Coastguard Worker std::unordered_set<std::string> files_to_drop;
380*288bf522SAndroid Build Coastguard Worker
381*288bf522SAndroid Build Coastguard Worker // Read file features.
382*288bf522SAndroid Build Coastguard Worker for (auto& reader : readers_) {
383*288bf522SAndroid Build Coastguard Worker FileFeature file;
384*288bf522SAndroid Build Coastguard Worker uint64_t read_pos = 0;
385*288bf522SAndroid Build Coastguard Worker bool error = false;
386*288bf522SAndroid Build Coastguard Worker while (reader->ReadFileFeature(read_pos, file, error)) {
387*288bf522SAndroid Build Coastguard Worker if (files_to_drop.count(file.path) != 0) {
388*288bf522SAndroid Build Coastguard Worker continue;
389*288bf522SAndroid Build Coastguard Worker }
390*288bf522SAndroid Build Coastguard Worker if (auto it = file_map.find(file.path); it == file_map.end()) {
391*288bf522SAndroid Build Coastguard Worker file_map.emplace(file.path, file);
392*288bf522SAndroid Build Coastguard Worker } else if (!it->second.Merge(file)) {
393*288bf522SAndroid Build Coastguard Worker LOG(WARNING)
394*288bf522SAndroid Build Coastguard Worker << file.path
395*288bf522SAndroid Build Coastguard Worker << " has address-conflict symbols in different record files. So drop its symbols.";
396*288bf522SAndroid Build Coastguard Worker files_to_drop.emplace(file.path);
397*288bf522SAndroid Build Coastguard Worker }
398*288bf522SAndroid Build Coastguard Worker }
399*288bf522SAndroid Build Coastguard Worker if (error) {
400*288bf522SAndroid Build Coastguard Worker return false;
401*288bf522SAndroid Build Coastguard Worker }
402*288bf522SAndroid Build Coastguard Worker }
403*288bf522SAndroid Build Coastguard Worker // Write file features.
404*288bf522SAndroid Build Coastguard Worker for (const auto& [file_path, file] : file_map) {
405*288bf522SAndroid Build Coastguard Worker if (files_to_drop.count(file_path) != 0) {
406*288bf522SAndroid Build Coastguard Worker continue;
407*288bf522SAndroid Build Coastguard Worker }
408*288bf522SAndroid Build Coastguard Worker FileFeature file_feature;
409*288bf522SAndroid Build Coastguard Worker file.ToFileFeature(&file_feature);
410*288bf522SAndroid Build Coastguard Worker if (!writer_->WriteFileFeature(file_feature)) {
411*288bf522SAndroid Build Coastguard Worker return false;
412*288bf522SAndroid Build Coastguard Worker }
413*288bf522SAndroid Build Coastguard Worker }
414*288bf522SAndroid Build Coastguard Worker return true;
415*288bf522SAndroid Build Coastguard Worker }
416*288bf522SAndroid Build Coastguard Worker
417*288bf522SAndroid Build Coastguard Worker std::vector<std::string> input_files_;
418*288bf522SAndroid Build Coastguard Worker std::vector<std::unique_ptr<RecordFileReader>> readers_;
419*288bf522SAndroid Build Coastguard Worker std::string output_file_;
420*288bf522SAndroid Build Coastguard Worker std::unique_ptr<RecordFileWriter> writer_;
421*288bf522SAndroid Build Coastguard Worker };
422*288bf522SAndroid Build Coastguard Worker
423*288bf522SAndroid Build Coastguard Worker } // namespace
424*288bf522SAndroid Build Coastguard Worker
RegisterMergeCommand()425*288bf522SAndroid Build Coastguard Worker void RegisterMergeCommand() {
426*288bf522SAndroid Build Coastguard Worker return RegisterCommand("merge", [] { return std::unique_ptr<Command>(new MergeCommand); });
427*288bf522SAndroid Build Coastguard Worker }
428*288bf522SAndroid Build Coastguard Worker
429*288bf522SAndroid Build Coastguard Worker } // namespace simpleperf
430